diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d3b529a69107060bb13a2285a3f0a2ab86f7d55..de027c57fd8cf34f84b4ba4dbb2f7a28f5bdd617 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,7 @@ endif() #--------------------------------------------------------------------------------------------------- #fg: moved to here from DD4hep.cmake to not force CMAKE_CXX_FLAGS upon dependent packages if ( DD4HEP_USE_CXX11 ) - set ( CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -pedantic -Wshadow -Wformat-security -Wno-long-long -Wdeprecated") + set ( CMAKE_CXX_FLAGS "-std=c++11 -ftls-model=global-dynamic -Wall -Wextra -pedantic -Wshadow -Wformat-security -Wno-long-long -Wdeprecated") add_definitions(-DDD4HEP_USE_CXX11) else() set( CMAKE_CXX_FLAGS "-Wall -Wextra -pedantic -Wshadow -Wformat-security -Wno-long-long -Wdeprecated") diff --git a/DDCore/include/DD4hep/Printout.h b/DDCore/include/DD4hep/Printout.h index 247646e2ad0bc56eed61a2918bb15f6e95f2fbbf..f2ed650a2ba8ba9e17463edbef564d2b85a6ab1c 100644 --- a/DDCore/include/DD4hep/Printout.h +++ b/DDCore/include/DD4hep/Printout.h @@ -185,6 +185,9 @@ namespace DD4hep { #endif // __CINT__ + /// Set new printout format for the 3 fields: source-level-message. All 3 are strings + std::string setPrintFormat(const std::string& new_format); + /// Set new print level. Returns the old print level PrintLevel setPrintLevel(PrintLevel new_level); diff --git a/DDCore/include/DD4hep/objects/BasicGrammar_inl.h b/DDCore/include/DD4hep/objects/BasicGrammar_inl.h index a2406a4bd2c156ad9e098b06358964ecc2e59d37..50f7ff56ae708cd9289c8f0f3b8aac45e86ab5b3 100644 --- a/DDCore/include/DD4hep/objects/BasicGrammar_inl.h +++ b/DDCore/include/DD4hep/objects/BasicGrammar_inl.h @@ -130,7 +130,7 @@ namespace DD4hep { } /// Helper function to parse data type - static std::string pre_parse_obj(const std::string& in) { + static inline std::string pre_parse_obj(const std::string& in) { std::string res = ""; res.reserve(1024); for(const char* c = in.c_str(); *c; ++c) { diff --git a/DDCore/src/BasicGrammarTypes.cpp b/DDCore/src/BasicGrammarTypes.cpp index 6e97c8de48b547b4435e131be23c9146800b33db..ce98b65141416c182012239aca2a3eecd87beb53 100644 --- a/DDCore/src/BasicGrammarTypes.cpp +++ b/DDCore/src/BasicGrammarTypes.cpp @@ -37,9 +37,9 @@ namespace ROOT { } } } -template class std::less<ROOT::Math::XYZPoint>; -template class std::less<ROOT::Math::XYZVector>; -template class std::less<ROOT::Math::PxPyPzEVector>; +template struct std::less<ROOT::Math::XYZPoint>; +template struct std::less<ROOT::Math::XYZVector>; +template struct std::less<ROOT::Math::PxPyPzEVector>; DD4HEP_DEFINE_PARSER_GRAMMAR_U_CONT(char) DD4HEP_DEFINE_PARSER_GRAMMAR_U_CONT(short) diff --git a/DDCore/src/Printout.cpp b/DDCore/src/Printout.cpp index ab19e52634e619db7af07f718aa743cc2692e8a7..3168c708f29cbf9422df142e94a5ab48142f8f0b 100644 --- a/DDCore/src/Printout.cpp +++ b/DDCore/src/Printout.cpp @@ -24,6 +24,8 @@ using namespace std; +static std::string print_fmt = "%-16s %5s %s"; + static size_t _the_printer(void*, DD4hep::PrintLevel lvl, const char* src, const char* text) { const char* p_lvl = "?????"; if ( lvl> DD4hep::ALWAYS ) lvl = DD4hep::ALWAYS; @@ -40,7 +42,7 @@ static size_t _the_printer(void*, DD4hep::PrintLevel lvl, const char* src, const default: break; } - size_t len = ::fprintf(stdout, "%-16s %5s %s",src,p_lvl,text); + size_t len = ::fprintf(stdout, print_fmt.c_str(), src, p_lvl, text); // size_t len = ::fputs(src, stdout); // len += fputs(": ", stdout); // len += fputs(text, stdout); @@ -280,6 +282,13 @@ DD4hep::PrintLevel DD4hep::printLevel() { return print_lvl; } +/// Set new printout format for the 3 fields: source-level-message. All 3 are strings +string DD4hep::setPrintFormat(const string& new_format) { + string old = print_fmt; + print_fmt = new_format; + return old; +} + /// Customize printer function void DD4hep::setPrinter(void* arg, output_function_t fcn) { print_arg = arg; diff --git a/DDCore/src/XML/DocumentHandler.cpp b/DDCore/src/XML/DocumentHandler.cpp index 61882d57f81c487f24d7ddc7d114b025f17fee29..0d334d47e37dd6617ba7406ce1fae9b2f89eddb0 100644 --- a/DDCore/src/XML/DocumentHandler.cpp +++ b/DDCore/src/XML/DocumentHandler.cpp @@ -188,9 +188,9 @@ Document DocumentHandler::load(Handle_t base, const XMLCh* fname) const { Document DocumentHandler::load(const std::string& fname) const { printout(DEBUG,"DocumentHandler","+++ Loading document URI: %s",fname.c_str()); - XMLURL xerurl = (const XMLCh*) Strng_t(fname); - string path = _toString(xerurl.getPath()); - string proto = _toString(xerurl.getProtocolName()); + XMLURL xerurl = (const XMLCh*) Strng_t(fname.find(":")==std::string::npos ? "file:"+fname : fname); + string path = _toString(xerurl.getPath()); + string proto = _toString(xerurl.getProtocolName()); dd4hep_ptr < XercesDOMParser > parser(make_parser(m_errHdlr.get())); printout(DEBUG,"DocumentHandler","+++ protocol:%s path:%s",proto.c_str(), path.c_str()); try { diff --git a/DDCore/src/XML/Layering.cpp b/DDCore/src/XML/Layering.cpp index 2f014946c83c141546f84cacb4a4a633b3415911..8bde57841ce8f3c8351412b49f9200da74ebe390 100644 --- a/DDCore/src/XML/Layering.cpp +++ b/DDCore/src/XML/Layering.cpp @@ -145,4 +145,6 @@ void Layering::sensitivePositionsInLayer(XML::Element e, std::vector<double>& se sens_pos.push_back(pos - slice.thickness()/2.); } } -} \ No newline at end of file +} + + diff --git a/DDEve/include/DDEve/DisplayConfiguration.h b/DDEve/include/DDEve/DisplayConfiguration.h index 5fde5f9a858899ab81054e50c3b67ba9db247fe5..c4e06b46a383a6f291ed14114b8b7d38ba497c5a 100644 --- a/DDEve/include/DDEve/DisplayConfiguration.h +++ b/DDEve/include/DDEve/DisplayConfiguration.h @@ -46,9 +46,10 @@ namespace DD4hep { COLLECTION=1<<5 }; struct Defaults { - char load_geo; - char show_evt; - short color; + char load_geo; + char show_evt; + short default_pad; + int color; float alpha; }; struct Calo3D : public Defaults { diff --git a/DDG4/CMakeLists.txt b/DDG4/CMakeLists.txt index 0383c15b33f66f37a517e5eab71287c048625906..5a19eab7fa46a3fcc300908fc1095b6870364231 100644 --- a/DDG4/CMakeLists.txt +++ b/DDG4/CMakeLists.txt @@ -25,6 +25,20 @@ dd4hep_add_dictionary( G__DDG4 SOURCES python/DDG4Dict.C ) dd4hep_add_plugin(DDG4Plugins GENERATED G__DDG4.cxx SOURCES plugins/*.cpp) +#--------------------------- Plugin library for the simulation framework --------- +dd4hep_add_dictionary(G__DDG4Python SOURCES src/python/DDG4Python.C ) +#--------------------------- Plugin library for the simulation framework --------- +dd4hep_add_dictionary(G__DDPython SOURCES tpython/DDPython.C ) +#--------------------------- Specialized python plugins -------------------------- +dd4hep_add_regular_library(DDPython + GENERATED G__DDPython.cxx + USES [ROOT REQUIRED COMPONENTS PyROOT] + OPTIONAL [PYTHON REQUIRED SOURCES tpython/DDPython.cpp]) +#--------------------------- Specialized python plugins -------------------------- +dd4hep_add_plugin(DDG4Python + GENERATED G__DDG4Python.cxx + LINK_LIBRARIES DDPython + OPTIONAL [PYTHON REQUIRED SOURCES src/python/*.cpp]) #--------------------------- LCIO Plugins for new simulation framework ----------- dd4hep_add_plugin(DDG4LCIO OPTIONAL [LCIO REQUIRED SOURCES lcio/*.cpp] ) @@ -37,6 +51,11 @@ dd4hep_add_executable(g4gdmlDisplay SOURCES g4gdmlDisplay.cpp) dd4hep_add_executable(g4FromXML SOURCES g4FromXML.cpp) #----------------------------------------------------------------------------------- dd4hep_add_executable(dd_sim SOURCES ddsim.cpp) +#---Helper to overcome deficiency of the python executable concerning multi-threading +dd4hep_add_executable(pyddg4 + LINK_LIBRARIES DDPython + USES [ROOT REQUIRED COMPONENTS PyROOT] + OPTIONAL [PYTHON REQUIRED SOURCES pyddg4.cpp]) #---Package installation procedure(s) ---------------------------------------------- dd4hep_install_dir(examples DESTINATION examples/DDG4) dd4hep_install_files(FILES python/*.py python/*.C DESTINATION python) diff --git a/DDG4/examples/CLICSidSimu.py b/DDG4/examples/SiDSim.py similarity index 85% rename from DDG4/examples/CLICSidSimu.py rename to DDG4/examples/SiDSim.py index 318e26eafff2c41fb12bb241fde680d5afe63b8e..f43e866fb4d94f37dc6787271da824296292f9bf 100644 --- a/DDG4/examples/CLICSidSimu.py +++ b/DDG4/examples/SiDSim.py @@ -5,6 +5,7 @@ from DDG4 import OutputLevel as Output from SystemOfUnits import * # # +print \ """ DD4hep simulation example setup using the python configuration @@ -22,10 +23,10 @@ def run(): geant4 = DDG4.Geant4(kernel,tracker='Geant4TrackerCombineAction') geant4.printDetectors() - # Configure UI + print "# Configure UI" geant4.setupCshUI() - # Configure G4 magnetic field tracking + print "# Configure G4 magnetic field tracking" field = geant4.addConfig('Geant4FieldTrackingSetupAction/MagFieldTrackingSetup') field.stepper = "HelixGeant4Runge" field.equation = "Mag_UsualEqRhs" @@ -41,14 +42,13 @@ def run(): print '+++++> ',field.name,'-> eps_max = ',field.eps_max print '+++++> ',field.name,'-> delta_one_step = ',field.delta_one_step - # Setup random generator + print "# Setup random generator" rndm = DDG4.Action(kernel,'Geant4Random/Random') rndm.Seed = 987654321 rndm.initialize() - rndm.showStatus() - rndm.Seed = 987654321 + ##rndm.showStatus() - # Configure Run actions + print "# Configure Run actions" run1 = DDG4.RunAction(kernel,'Geant4TestRunAction/RunInit') run1.Property_int = 12345 run1.Property_double = -5e15*keV @@ -58,13 +58,15 @@ def run(): kernel.registerGlobalAction(run1) kernel.runAction().adopt(run1) - # Configure Event actions + print "# Configure Event actions" prt = DDG4.EventAction(kernel,'Geant4ParticlePrint/ParticlePrint') prt.OutputLevel = Output.INFO prt.OutputType = 3 # Print both: table and tree kernel.eventAction().adopt(prt) - # Configure I/O + print """ + Configure I/O + """ evt_lcio = geant4.setupLCIOOutput('LcioOutput','CLICSiD_'+time.strftime('%Y-%m-%d_%H-%M')) evt_lcio.OutputLevel = Output.ERROR @@ -76,51 +78,51 @@ def run(): kernel.generatorAction().adopt(gen) #VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV - """ + print """ Generation of isotrope tracks of a given multiplicity with overlay: """ - # First particle generator: pi+ + print "# First particle generator: pi+" gen = DDG4.GeneratorAction(kernel,"Geant4IsotropeGenerator/IsotropPi+"); + gen.Mask = 1 gen.Particle = 'pi+' - gen.Energy = 100 * GeV + gen.Energy = 100 * GeV gen.Multiplicity = 2 - gen.Mask = 1 kernel.generatorAction().adopt(gen) - # Install vertex smearing for this interaction + print "# Install vertex smearing for this interaction" gen = DDG4.GeneratorAction(kernel,"Geant4InteractionVertexSmear/SmearPi+"); - gen.Mask = 1 + gen.Mask = 1 gen.Offset = (20*mm, 10*mm, 10*mm, 0*ns) - gen.Sigma = (4*mm, 1*mm, 1*mm, 0*ns) + gen.Sigma = (4*mm, 1*mm, 1*mm, 0*ns) kernel.generatorAction().adopt(gen) - # Second particle generator: e- + print "# Second particle generator: e-" gen = DDG4.GeneratorAction(kernel,"Geant4IsotropeGenerator/IsotropE-"); + gen.Mask = 2 gen.Particle = 'e-' - gen.Energy = 25 * GeV + gen.Energy = 25 * GeV gen.Multiplicity = 3 - gen.Mask = 2 kernel.generatorAction().adopt(gen) - # Install vertex smearing for this interaction + print " Install vertex smearing for this interaction" gen = DDG4.GeneratorAction(kernel,"Geant4InteractionVertexSmear/SmearE-"); - gen.Mask = 2 + gen.Mask = 2 gen.Offset = (-20*mm, -10*mm, -10*mm, 0*ns) - gen.Sigma = (12*mm, 8*mm, 8*mm, 0*ns) + gen.Sigma = (12*mm, 8*mm, 8*mm, 0*ns) kernel.generatorAction().adopt(gen) #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - # Merge all existing interaction records + print "# Merge all existing interaction records" gen = DDG4.GeneratorAction(kernel,"Geant4InteractionMerger/InteractionMerger") gen.OutputLevel = 4 #generator_output_level gen.enableUI() kernel.generatorAction().adopt(gen) - # Finally generate Geant4 primaries + print "# Finally generate Geant4 primaries" gen = DDG4.GeneratorAction(kernel,"Geant4PrimaryHandler/PrimaryHandler") gen.OutputLevel = 4 #generator_output_level gen.enableUI() kernel.generatorAction().adopt(gen) - # And handle the simulation particles. + print "# ....and handle the simulation particles." part = DDG4.GeneratorAction(kernel,"Geant4ParticleHandler/ParticleHandler") kernel.generatorAction().adopt(part) #part.SaveProcesses = ['conv','Decay'] @@ -134,7 +136,7 @@ def run(): user.enableUI() part.adopt(user) - # Setup global filters fur use in sensntive detectors + print "# Setup global filters fur use in sensntive detectors" f1 = DDG4.Filter(kernel,'GeantinoRejectFilter/GeantinoRejector') f2 = DDG4.Filter(kernel,'ParticleRejectFilter/OpticalPhotonRejector') f2.particle = 'opticalphoton' @@ -148,7 +150,7 @@ def run(): kernel.registerGlobalFilter(f3) kernel.registerGlobalFilter(f4) - # First the tracking detectors + print "# First the tracking detectors" seq,act = geant4.setupTracker('SiVertexBarrel') seq.adopt(f1) #seq.adopt(f4) @@ -161,7 +163,7 @@ def run(): seq,act = geant4.setupTracker('SiTrackerBarrel') seq,act = geant4.setupTracker('SiTrackerEndcap') seq,act = geant4.setupTracker('SiTrackerForward') - # Now the calorimeters + print "# Now setup the calorimeters" seq,act = geant4.setupCalorimeter('EcalBarrel') seq,act = geant4.setupCalorimeter('EcalEndcap') seq,act = geant4.setupCalorimeter('HcalBarrel') @@ -172,7 +174,7 @@ def run(): seq,act = geant4.setupCalorimeter('LumiCal') seq,act = geant4.setupCalorimeter('BeamCal') - # Now build the physics list: + print "# Now build the physics list:" phys = geant4.setupPhysics('QGSP_BERT') ph = DDG4.PhysicsList(kernel,'Geant4PhysicsList/Myphysics') ph.addParticleConstructor('G4BosonConstructor') diff --git a/DDG4/examples/SiDSim_MT.py b/DDG4/examples/SiDSim_MT.py new file mode 100644 index 0000000000000000000000000000000000000000..b0d514656c80402023133151843b8a4482a1b983 --- /dev/null +++ b/DDG4/examples/SiDSim_MT.py @@ -0,0 +1,190 @@ +# +# +import os, time, DDG4 +from DDG4 import OutputLevel as Output +from SystemOfUnits import * +# +# +print \ +""" + + DD4hep simulation example setup DDG4 + in multi-threaded mode using the python configuration + + @author M.Frank + @version 1.0 + +""" + + +def setupWorker(geant4): + kernel = geant4.kernel() + print '#PYTHON: +++ Creating Geant4 worker thread ....' + print "#PYTHON: Configure Run actions" + run1 = DDG4.RunAction(kernel,'Geant4TestRunAction/RunInit') + run1.Property_int = 12345 + run1.Property_double = -5e15*keV + run1.Property_string = 'Startrun: Hello_2' + print run1.Property_string, run1.Property_double, run1.Property_int + run1.enableUI() + kernel.registerGlobalAction(run1) + kernel.runAction().adopt(run1) + + print "#PYTHON: Configure Event actions" + prt = DDG4.EventAction(kernel,'Geant4ParticlePrint/ParticlePrint') + prt.OutputLevel = Output.INFO + prt.OutputType = 3 # Print both: table and tree + kernel.eventAction().adopt(prt) + + print "\n#PYTHON: Configure I/O\n" + evt_lcio = geant4.setupLCIOOutput('LcioOutput','CLICSiD_'+time.strftime('%Y-%m-%d_%H-%M')) + evt_lcio.OutputLevel = Output.ERROR + + evt_root = geant4.setupROOTOutput('RootOutput','CLICSiD_'+time.strftime('%Y-%m-%d_%H-%M')) + + generator_output_level = Output.INFO + + gen = DDG4.GeneratorAction(kernel,"Geant4GeneratorActionInit/GenerationInit") + kernel.generatorAction().adopt(gen) + #VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV + print "#PYTHON:\n#PYTHON: Generation of isotrope tracks of a given multiplicity with overlay:\n#PYTHON:" + print "#PYTHON: First particle generator: pi+" + gen = DDG4.GeneratorAction(kernel,"Geant4IsotropeGenerator/IsotropPi+"); + gen.Mask = 1 + gen.Particle = 'pi+' + gen.Energy = 100 * GeV + gen.Multiplicity = 2 + kernel.generatorAction().adopt(gen) + print "#PYTHON: Install vertex smearing for this interaction" + gen = DDG4.GeneratorAction(kernel,"Geant4InteractionVertexSmear/SmearPi+"); + gen.Mask = 1 + gen.Offset = (20*mm, 10*mm, 10*mm, 0*ns) + gen.Sigma = (4*mm, 1*mm, 1*mm, 0*ns) + kernel.generatorAction().adopt(gen) + + print "#PYTHON: Second particle generator: e-" + gen = DDG4.GeneratorAction(kernel,"Geant4IsotropeGenerator/IsotropE-"); + gen.Mask = 2 + gen.Particle = 'e-' + gen.Energy = 25 * GeV + gen.Multiplicity = 3 + kernel.generatorAction().adopt(gen) + print "#PYTHON: Install vertex smearing for this interaction" + gen = DDG4.GeneratorAction(kernel,"Geant4InteractionVertexSmear/SmearE-"); + gen.Mask = 2 + gen.Offset = (-20*mm, -10*mm, -10*mm, 0*ns) + gen.Sigma = (12*mm, 8*mm, 8*mm, 0*ns) + kernel.generatorAction().adopt(gen) + #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + print "#PYTHON: Merge all existing interaction records" + gen = DDG4.GeneratorAction(kernel,"Geant4InteractionMerger/InteractionMerger") + gen.OutputLevel = 4 #generator_output_level + gen.enableUI() + kernel.generatorAction().adopt(gen) + + print "#PYTHON: Finally generate Geant4 primaries" + gen = DDG4.GeneratorAction(kernel,"Geant4PrimaryHandler/PrimaryHandler") + gen.OutputLevel = 4 #generator_output_level + gen.enableUI() + kernel.generatorAction().adopt(gen) + + print "#PYTHON: ....and handle the simulation particles." + part = DDG4.GeneratorAction(kernel,"Geant4ParticleHandler/ParticleHandler") + kernel.generatorAction().adopt(part) + #part.SaveProcesses = ['conv','Decay'] + part.SaveProcesses = ['Decay'] + part.MinimalKineticEnergy = 100*MeV + part.OutputLevel = 5 # generator_output_level + part.enableUI() + user = DDG4.Action(kernel,"Geant4TCUserParticleHandler/UserParticleHandler") + user.TrackingVolume_Zmax = DDG4.EcalEndcap_zmin + user.TrackingVolume_Rmax = DDG4.EcalBarrel_rmin + user.enableUI() + part.adopt(user) + print '#PYTHON: +++ Geant4 worker thread configured successfully....' + return 1 + +def setupMaster(geant4): + kernel = geant4.master() + print '#PYTHON: +++ Setting up master thread for ',kernel.NumberOfThreads,' workers.' + return 1 + +def setupSensitives(geant4): + print "#PYTHON: Setting up all sensitive detectors" + geant4.printDetectors() + print "#PYTHON: First the tracking detectors" + seq,act = geant4.setupTracker('SiVertexBarrel') + seq,act = geant4.setupTracker('SiVertexEndcap') + seq,act = geant4.setupTracker('SiTrackerBarrel') + seq,act = geant4.setupTracker('SiTrackerEndcap') + seq,act = geant4.setupTracker('SiTrackerForward') + print "#PYTHON: Now setup the calorimeters" + seq,act = geant4.setupCalorimeter('EcalBarrel') + seq,act = geant4.setupCalorimeter('EcalEndcap') + seq,act = geant4.setupCalorimeter('HcalBarrel') + seq,act = geant4.setupCalorimeter('HcalEndcap') + seq,act = geant4.setupCalorimeter('HcalPlug') + seq,act = geant4.setupCalorimeter('MuonBarrel') + seq,act = geant4.setupCalorimeter('MuonEndcap') + seq,act = geant4.setupCalorimeter('LumiCal') + seq,act = geant4.setupCalorimeter('BeamCal') + return 1 + +def run(): + kernel = DDG4.Kernel() + lcdd = kernel.lcdd() + install_dir = os.environ['DD4hepINSTALL'] + DDG4.Core.setPrintFormat("%-32s %6s %s") + kernel.loadGeometry("file:"+install_dir+"/DDDetectors/compact/SiD.xml") + DDG4.importConstants(lcdd) + + kernel.NumberOfThreads = 3 + geant4 = DDG4.Geant4(kernel,tracker='Geant4TrackerCombineAction') + print "# Configure UI" + geant4.setupCshUI() + + print "# Geant4 user initialization action" + geant4.addUserInitialization(worker=setupWorker, worker_args=(geant4,), + master=setupMaster,master_args=(geant4,)) + + print "# Configure G4 geometry setup" + seq,act = geant4.addDetectorConstruction("Geant4DetectorGeometryConstruction/ConstructGeo") + + print "# Configure G4 sensitive detectors: python setup callback" + seq,act = geant4.addDetectorConstruction("Geant4PythonDetectorConstruction/SetupSD", + sensitives=setupSensitives,sensitives_args=(geant4,)) + print "# Configure G4 sensitive detectors: atach'em to the sensitive volumes" + seq,act = geant4.addDetectorConstruction("Geant4DetectorSensitivesConstruction/ConstructSD") + # allow_threads=True) + + print "# Configure G4 magnetic field tracking" + seq,field = geant4.addDetectorConstruction("Geant4FieldTrackingConstruction/MagFieldTrackingSetup") + field.stepper = "HelixGeant4Runge" + field.equation = "Mag_UsualEqRhs" + field.eps_min = 5e-05 * mm + field.eps_max = 0.001 * mm + field.min_chord_step = 0.01 * mm + field.delta_chord = 0.25 * mm + field.delta_intersection = 1e-05 * mm + field.delta_one_step = 0.001 * mm + print '+++++> ',field.name,'-> stepper = ',field.stepper + print '+++++> ',field.name,'-> equation = ',field.equation + print '+++++> ',field.name,'-> eps_min = ',field.eps_min + print '+++++> ',field.name,'-> eps_max = ',field.eps_max + print '+++++> ',field.name,'-> delta_one_step = ',field.delta_one_step + + print "# Setup random generator" + rndm = DDG4.Action(kernel,'Geant4Random/Random') + rndm.Seed = 987654321 + rndm.initialize() + ##rndm.showStatus() + + print "# Now build the physics list:" + phys = geant4.setupPhysics('QGSP_BERT') + phys.dump() + + geant4.run() + +if __name__ == "__main__": + run() diff --git a/DDG4/examples/SiD_Markus.py b/DDG4/examples/SiD_Markus.py index a96b8f4b11467cc31647c8d22febc9cd656093e2..23769ca60c0560a80ae85274800960078c90aeb6 100644 --- a/DDG4/examples/SiD_Markus.py +++ b/DDG4/examples/SiD_Markus.py @@ -4,6 +4,7 @@ import os, time, DDG4 from DDG4 import OutputLevel as Output from SystemOfUnits import * # +global geant4 # """ @@ -13,40 +14,12 @@ from SystemOfUnits import * @version 1.0 """ -def run(): - kernel = DDG4.Kernel() - lcdd = kernel.lcdd() - install_dir = os.environ['DD4hepINSTALL'] - kernel.loadGeometry("file:"+install_dir+"/DDDetectors/compact/SiD_Markus.xml") - DDG4.importConstants(lcdd) - DDG4.Core.setPrintLevel(Output.WARNING) - - geant4 = DDG4.Geant4(kernel,tracker='Geant4TrackerWeightedAction') - geant4.printDetectors() - # Configure UI - geant4.setupCshUI() - - # Configure G4 magnetic field tracking - field = geant4.addConfig('Geant4FieldTrackingSetupAction/MagFieldTrackingSetup') - field.stepper = "HelixGeant4Runge" - field.equation = "Mag_UsualEqRhs" - field.eps_min = 5e-05 * mm - field.eps_max = 0.001 * mm - field.min_chord_step = 0.01 * mm - field.delta_chord = 0.25 * mm - field.delta_intersection = 1e-05 * mm - field.delta_one_step = 0.001 * mm - print '+++++> ',field.name,'-> stepper = ',field.stepper - print '+++++> ',field.name,'-> equation = ',field.equation - print '+++++> ',field.name,'-> eps_min = ',field.eps_min - print '+++++> ',field.name,'-> eps_max = ',field.eps_max - print '+++++> ',field.name,'-> delta_one_step = ',field.delta_one_step - - # Setup random generator - rndm = DDG4.Action(kernel,'Geant4Random/Random') - rndm.Seed = 987654321 - rndm.initialize() +def setupWorker(): + k = DDG4.Kernel() + kernel = k.worker() + print 'PYTHON: +++ Creating Geant4 worker thread ....' + # Configure Run actions run1 = DDG4.RunAction(kernel,'Geant4TestRunAction/RunInit') run1.Property_int = 12345 @@ -143,11 +116,15 @@ def run(): user.TrackingVolume_Rmax = DDG4.EcalBarrel_rmin user.enableUI() part.adopt(user) + print 'PYTHON: +++ Geant4 worker thread configured successfully....' + return 1 + +def setupMaster(): + print 'PYTHON: +++ Setting up master thread.....' + return 1 - # Setup global filters fur use in sensntive detectors - f1 = DDG4.Filter(kernel,'GeantinoRejectFilter/GeantinoRejector') - kernel.registerGlobalFilter(f1) - +def setupSensitives(): + global geant4 # First the tracking detectors seq,act = geant4.setupTracker('SiVertexBarrel') act.OutputLevel = Output.ERROR @@ -155,6 +132,75 @@ def run(): seq,act = geant4.setupTracker('SiVertexEndcap') act.OutputLevel = Output.ERROR act.CollectSingleDeposits = False + print 'PYTHON: +++ Setting up Geant4 sensitive detectors for worker thread.....' + return 1 + +def dummy_sd(): + print 'PYTHON: +++ Setting up DUMMY Geant4 sensitive detectors for worker thread.....' + return 1 + +def dummy_geom(): + print 'PYTHON: +++ Setting up DUMMY Geant4 geometry for worker thread.....' + return 1 + + +def run(): + global geant4 + kernel = DDG4.Kernel() + lcdd = kernel.lcdd() + install_dir = os.environ['DD4hepINSTALL'] + kernel.loadGeometry("file:"+install_dir+"/DDDetectors/compact/SiD_Markus.xml") + DDG4.importConstants(lcdd) + DDG4.Core.setPrintLevel(Output.DEBUG) + DDG4.Core.setPrintFormat("%-32s %6s %s") + + kernel.NumberOfThreads = 3 + geant4 = DDG4.Geant4(kernel,tracker='Geant4TrackerWeightedAction') + geant4.printDetectors() + # Configure UI + geant4.setupCshUI() + + # Geant4 user initialization action + geant4.addUserInitialization(worker=setupWorker, master=setupMaster) + + # Configure G4 geometry setup + seq,act = geant4.addDetectorConstruction("Geant4DetectorGeometryConstruction/ConstructGeo") + + # Configure G4 magnetic field tracking + seq,fld = geant4.addDetectorConstruction("Geant4FieldTrackingConstruction/MagFieldTrackingSetup") + fld.stepper = "HelixGeant4Runge" + fld.equation = "Mag_UsualEqRhs" + fld.eps_min = 5e-05 * mm + fld.eps_max = 0.001 * mm + fld.min_chord_step = 0.01 * mm + fld.delta_chord = 0.25 * mm + fld.delta_intersection = 1e-05 * mm + fld.delta_one_step = 0.001 * mm + print '+++++> ',fld.name,'-> stepper = ',fld.stepper + print '+++++> ',fld.name,'-> equation = ',fld.equation + print '+++++> ',fld.name,'-> eps_min = ',fld.eps_min + print '+++++> ',fld.name,'-> eps_max = ',fld.eps_max + print '+++++> ',fld.name,'-> delta_one_step = ',fld.delta_one_step + + seq,act = geant4.addDetectorConstruction("Geant4PythonDetectorConstruction/DummyDet", + geometry=dummy_geom, + sensitives=dummy_sd) + # Configure G4 sensitive detectors + seq,act = geant4.addDetectorConstruction("Geant4PythonDetectorConstruction/SetupSD", + sensitives=setupSensitives) + + # Configure G4 sensitive detectors + seq,act = geant4.addDetectorConstruction("Geant4DetectorSensitivesConstruction/ConstructSD", + allow_threads=True) + + # Setup random generator + rndm = DDG4.Action(kernel,'Geant4Random/Random') + rndm.Seed = 987654321 + rndm.initialize() + + # Setup global filters fur use in sensntive detectors + f1 = DDG4.Filter(kernel,'GeantinoRejectFilter/GeantinoRejector') + kernel.registerGlobalFilter(f1) #seq,act = geant4.setupTracker('SiTrackerBarrel') #seq,act = geant4.setupTracker('SiTrackerEndcap') @@ -174,12 +220,15 @@ def run(): phys = geant4.setupPhysics('QGSP_BERT') phys.dump() - kernel.configure() - kernel.initialize() + #kernel.configure() + #kernel.initialize() #DDG4.setPrintLevel(Output.DEBUG) - kernel.run() - kernel.terminate() + #kernel.run() + #kernel.terminate() + return 1 if __name__ == "__main__": + import sys + print sys.argv run() diff --git a/DDG4/examples/testDDPython.py b/DDG4/examples/testDDPython.py new file mode 100644 index 0000000000000000000000000000000000000000..09de2e3ee758ad1e21e4c7ddb63db986cce66c7d --- /dev/null +++ b/DDG4/examples/testDDPython.py @@ -0,0 +1,68 @@ +from ROOT import gSystem +gSystem.Load('libDDPython') +from ROOT import DD4hep as Core + +name_space = __import__(__name__) +def import_namespace_item(ns,nam): + scope = getattr(name_space,ns) + attr = getattr(scope,nam) + setattr(name_space,nam,attr) + return attr + +def a_func(): + print 'Hello world' + return 1 + +class a_class: + def __init__(self): + pass + def fcn(self): + print 'Hello world from member function fcn' + return 1 + def fcn_except(self,args,aa): + print 'Hello world from member function fcn1 a1=',args,' a2=',aa + raise RuntimeError('Exception from python test object a_class') + return 6 + + +py = import_namespace_item('Core','DDPython') + +print '+++++ Test: Execute statements in python with C++ indirection' +py.instance().execute('import sys') +py.instance().execute('print "Arguments:", sys.argv') +print '\n' + +obj=a_class() +import sys, traceback + +print '+++++ Test: simple function call' +ret = py.instance().call(a_func,None) +print 'ret:',ret +print '\n' + +print '+++++ Test: object method call' +ret = py.instance().call(obj.fcn,None) +print 'ret:',ret +print '\n' + +print '+++++ Test: object method call with non callable' +try: + ret = py.instance().call(1,None) + print 'ret:',ret +except: + traceback.print_exc() +print '\n' + +print '+++++ Test: object method call with exception in python callback' +try: + ret = py.instance().call(obj.fcn_except,(1,[1,2,3,4,5,6],)) + print 'ret:',ret +except: + traceback.print_exc() +print '\n' +print '+++++ All Done....\n\n' + +#py.instance().prompt() + +sys.exit(0) + diff --git a/DDG4/include/DDG4/ComponentProperties.h b/DDG4/include/DDG4/ComponentProperties.h index a595d967874cf739908fe99a3ec6ce2fcdc45ab0..488acaa8dfa2fe30ed41d061663e296a7a594f1c 100644 --- a/DDG4/include/DDG4/ComponentProperties.h +++ b/DDG4/include/DDG4/ComponentProperties.h @@ -226,6 +226,8 @@ namespace DD4hep { template <typename FUNCTOR> void for_each(FUNCTOR& func) { std::for_each(m_properties.begin(), m_properties.end(), func); } + /// Export properties of another instance + void adopt(const PropertyManager& copy); /// Dump string values void dump() const; }; diff --git a/DDG4/include/DDG4/Geant4Action.h b/DDG4/include/DDG4/Geant4Action.h index bc71dcacf3f4bffb348d15d92b293e4054bf5f97..7080256c8d74d4a312c0061e67680a0df4c904b0 100644 --- a/DDG4/include/DDG4/Geant4Action.h +++ b/DDG4/include/DDG4/Geant4Action.h @@ -89,23 +89,21 @@ namespace DD4hep { class Geant4Action { protected: /// Reference to the Geant4 context - Geant4Context m_context; + Geant4Context* m_context; /// Control directory of this action Geant4UIMessenger* m_control; /// Default property: Output level - int m_outputLevel; + int m_outputLevel; /// Default property: Flag to create control instance - bool m_needsControl; + bool m_needsControl; /// Action name - std::string m_name; + std::string m_name; /// Property pool - PropertyManager m_properties; + PropertyManager m_properties; /// Reference count. Initial value: 1 - long m_refCount; + long m_refCount; - //fg: ContextUpdate needs to be public for the clang compiler - // as it is used in SequenceHdl::setContextToClients() public: /// Functor to update the context of a Geant4Action object /** @@ -113,18 +111,30 @@ namespace DD4hep { * \version 1.0 * \ingroup DD4HEP_SIMULATION */ - class ContextUpdate { - public: + class ContextSwap { /// reference to the context; - const Geant4Context* context; + Geant4Context* context; + Geant4Action* action; + public: /// Constructor - ContextUpdate(const Geant4Context* c=0) : context(c) {} - /// Callback - void operator()(Geant4Action* action) const; + ContextSwap(Geant4Action* a,Geant4Context* c) : action(a) { + context = action->context(); + action->updateContext(c); + } + /// Destructor + ~ContextSwap() { + action->updateContext(context); + } }; - friend class ContextUpdate; + protected: + /// Functor to access elements by name + struct FindByName { + std::string _n; + FindByName(const std::string& n) : _n(n) {} + bool operator()(const Geant4Action* a) { return a->name() == _n; } + }; /// Actor class to manipulate action groups /** * \author M.Frank @@ -161,12 +171,18 @@ namespace DD4hep { typename _V::iterator end() { return m_v.end(); } typename _V::const_iterator begin() const { return m_v.begin(); } typename _V::const_iterator end() const { return m_v.end(); } + /// Context updates - void operator()(const ContextUpdate& context) { - if (m_v.empty()) - return; - for (typename _V::iterator i = m_v.begin(); i != m_v.end(); ++i) - context(*i); + void updateContext(Geant4Context* ctxt) { + (*this)(&T::updateContext,ctxt); + } + /// Element access by name + template <typename F> typename _V::value_type get(const F& f) const { + if (!m_v.empty()) { + typename _V::const_iterator i=std::find_if(m_v.begin(),m_v.end(),f); + return i==m_v.end() ? 0 : (*i); + } + return 0; } /// NON-CONST actions template <typename R, typename Q> void operator()(R (Q::*pmf)()) { @@ -245,9 +261,15 @@ namespace DD4hep { /// Decrease reference count. Implicit destruction long release(); /// Access the context - const Geant4Context* context() const { - return &m_context; + Geant4Context* context() const { + return m_context; + } + /// Set or update client context + virtual void updateContext(Geant4Context* ctxt) { + m_context = ctxt; } + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); /// Access name of the action const std::string& name() const { return m_name; @@ -290,7 +312,7 @@ namespace DD4hep { /// Install command control messenger if wanted virtual void installCommandMessenger(); /// Install property control messenger if wanted - void installPropertyMessenger(); + virtual void installPropertyMessenger(); /// Support for messages with variable output level using output level void print(const char* fmt, ...) const; diff --git a/DDG4/include/DDG4/Geant4Config.h b/DDG4/include/DDG4/Geant4Config.h index b8520a291c8b2faa93fa852c42288d6cd862bf25..4d5a05dbc5e5fe24764380b63c5a3c1245a8f36b 100644 --- a/DDG4/include/DDG4/Geant4Config.h +++ b/DDG4/include/DDG4/Geant4Config.h @@ -40,6 +40,7 @@ namespace DD4hep { class Geant4ActionPhase; class Geant4GeneratorAction; class Geant4PhysicsList; + class Geant4UserInitialization; class Geant4UserParticleHandler; class Geant4GeneratorActionSequence; class Geant4RunActionSequence; @@ -49,6 +50,9 @@ namespace DD4hep { class Geant4StackingActionSequence; class Geant4PhysicsListActionSequence; class Geant4SensDetActionSequence; + class Geant4UserInitializationSequence; + class Geant4DetectorConstruction; + class Geant4DetectorConstructionSequence; /// Convenience namespace to ease the setupup of DDG4 applications namespace Setup { @@ -56,28 +60,32 @@ namespace DD4hep { typedef Geant4Kernel Kernel; //typedef Geant4Handle<Geant4Kernel> KernelH; // Actions - typedef Geant4Handle<Geant4Action> Action; - typedef Geant4Handle<Geant4Filter> Filter; - typedef Geant4Handle<Geant4PhaseAction> PhaseAction; - typedef Geant4Handle<Geant4GeneratorAction> GenAction; - typedef Geant4Handle<Geant4RunAction> RunAction; - typedef Geant4Handle<Geant4EventAction> EventAction; - typedef Geant4Handle<Geant4TrackingAction> TrackAction; - typedef Geant4Handle<Geant4StackingAction> StackAction; - typedef Geant4Handle<Geant4SteppingAction> StepAction; - typedef Geant4Handle<Geant4PhysicsList> PhysicsList; - typedef Geant4Handle<Geant4ActionPhase> Phase; - typedef Geant4Handle<Geant4Sensitive> Sensitive; + typedef Geant4Handle<Geant4Action> Action; + typedef Geant4Handle<Geant4Filter> Filter; + typedef Geant4Handle<Geant4PhaseAction> PhaseAction; + typedef Geant4Handle<Geant4GeneratorAction> GenAction; + typedef Geant4Handle<Geant4RunAction> RunAction; + typedef Geant4Handle<Geant4EventAction> EventAction; + typedef Geant4Handle<Geant4TrackingAction> TrackAction; + typedef Geant4Handle<Geant4StackingAction> StackAction; + typedef Geant4Handle<Geant4SteppingAction> StepAction; + typedef Geant4Handle<Geant4PhysicsList> PhysicsList; + typedef Geant4Handle<Geant4ActionPhase> Phase; + typedef Geant4Handle<Geant4Sensitive> Sensitive; + typedef Geant4Handle<Geant4UserInitialization> Initialization; + typedef Geant4Handle<Geant4DetectorConstruction> DetectorConstruction; // Sequences - typedef Geant4Handle<Geant4SensDetActionSequence> SensitiveSeq; - typedef Geant4Handle<Geant4GeneratorActionSequence> GeneratorSeq; - typedef Geant4Handle<Geant4RunActionSequence> RunActionSeq; - typedef Geant4Handle<Geant4EventActionSequence> EventActionSeq; - typedef Geant4Handle<Geant4TrackingActionSequence> TrackActionSeq; - typedef Geant4Handle<Geant4SteppingActionSequence> StepActionSeq; - typedef Geant4Handle<Geant4StackingActionSequence> StackActionSeq; - typedef Geant4Handle<Geant4PhysicsListActionSequence> PhysicsActionSeq; + typedef Geant4Handle<Geant4SensDetActionSequence> SensitiveSeq; + typedef Geant4Handle<Geant4GeneratorActionSequence> GeneratorSeq; + typedef Geant4Handle<Geant4RunActionSequence> RunActionSeq; + typedef Geant4Handle<Geant4EventActionSequence> EventActionSeq; + typedef Geant4Handle<Geant4TrackingActionSequence> TrackActionSeq; + typedef Geant4Handle<Geant4SteppingActionSequence> StepActionSeq; + typedef Geant4Handle<Geant4StackingActionSequence> StackActionSeq; + typedef Geant4Handle<Geant4PhysicsListActionSequence> PhysicsActionSeq; + typedef Geant4Handle<Geant4UserInitializationSequence> InitializationSeq; + typedef Geant4Handle<Geant4DetectorConstructionSequence> DetectorConstructionSeq; } } // End namespace Simulation @@ -93,9 +101,11 @@ namespace DD4hep { #include "DDG4/Geant4TrackingAction.h" #include "DDG4/Geant4SteppingAction.h" #include "DDG4/Geant4StackingAction.h" +#include "DDG4/Geant4DetectorConstruction.h" #include "DDG4/Geant4ActionPhase.h" #include "DDG4/Geant4SensDetAction.h" #include "DDG4/Geant4ParticleHandler.h" +#include "DDG4/Geant4UserInitialization.h" #include "DDG4/Geant4UserParticleHandler.h" #include "DDG4/ComponentUtils.h" #include "DD4hep/LCDD.h" diff --git a/DDG4/include/DDG4/Geant4Context.h b/DDG4/include/DDG4/Geant4Context.h index e84471a22b34bd2774898e5d1b72864b68af9f83..958e360b013673e3e3cc41e9f72e2e9414be94f4 100644 --- a/DDG4/include/DDG4/Geant4Context.h +++ b/DDG4/include/DDG4/Geant4Context.h @@ -166,6 +166,7 @@ namespace DD4hep { * \ingroup DD4HEP_SIMULATION */ class Geant4Context { + friend class Geant4Kernel; public: #ifdef R__DICTIONARY_FILENAME /// ROOT does not know how to process the nested ns otherwise @@ -176,9 +177,9 @@ namespace DD4hep { Geant4Kernel* m_kernel; Geant4Run* m_run; Geant4Event* m_event; - public: /// Default constructor Geant4Context(Geant4Kernel* kernel); + public: /// Default destructor virtual ~Geant4Context(); /// Set the geant4 run reference diff --git a/DDG4/include/DDG4/Geant4Converter.h b/DDG4/include/DDG4/Geant4Converter.h index 06c261ee26584785d32eb0cd52e9afd8618e7555..901fd40cbbb0c85500a263134062b502d81dde11 100644 --- a/DDG4/include/DDG4/Geant4Converter.h +++ b/DDG4/include/DDG4/Geant4Converter.h @@ -76,14 +76,11 @@ namespace DD4hep { /// Convert the geometry type LimitSet into the corresponding Geant4 object(s). virtual void* handleLimitSet(LimitSet limitset, const std::set<const TGeoVolume*>& volumes) const; - /// Convert the geometry type SensitiveDetector into the corresponding Geant4 object(s). - virtual void* handleSensitive(SensitiveDetector sens_det, const std::set<const TGeoVolume*>& volumes) const; - /// Handle the geant 4 specific properties void handleProperties(LCDD::Properties& prp) const; /// Print the geometry type SensitiveDetector - virtual void* printSensitive(SensitiveDetector sens_det, const std::set<const TGeoVolume*>& volumes) const; + virtual void printSensitive(SensitiveDetector sens_det, const std::set<const TGeoVolume*>& volumes) const; /// Print Geant4 placement virtual void* printPlacement(const std::string& name, const TGeoNode* node) const; diff --git a/DDG4/include/DDG4/Geant4DetectorConstruction.h b/DDG4/include/DDG4/Geant4DetectorConstruction.h index 8e52a7e694224e54a3381bf4b78794506cd7e03f..f925d39272a3dc64eaf08e3e3598e64d4a515d62 100644 --- a/DDG4/include/DDG4/Geant4DetectorConstruction.h +++ b/DDG4/include/DDG4/Geant4DetectorConstruction.h @@ -16,12 +16,14 @@ #define DD4HEP_GEANT4DETECTORCONSTRUCTION_H // Framework include files -#include "DD4hep/Printout.h" #include "DDG4/Geant4Action.h" #include "DDG4/Geant4GeometryInfo.h" -// Geant4 include files -#include "G4VUserDetectorConstruction.hh" +// Forward declarations +class G4VUserDetectorConstruction; +class G4VSensitiveDetector; +class G4LogicalVolume; + /// Namespace for the AIDA detector description toolkit namespace DD4hep { @@ -36,29 +38,109 @@ namespace DD4hep { // Forward declarations class Geant4Kernel; + class Geant4DetectorConstruction; + class Geant4DetectorConstructionContext; + class Geant4DetectorConstructionSequence; + + /// Geant4 detector construction context definition. + /** + * Detector construction context to allow the workers a simplified + * access to the object created. + * + * The context is a stack based object. Do not keep a pointer to + * The object scope does not span beyond the actional function call. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + struct Geant4DetectorConstructionContext { + /// Reference to geometry object + Geometry::LCDD& lcdd; + /// Reference to the world after construction + G4VPhysicalVolume* world; + /// The cached geometry information + Geant4GeometryInfo* geometry; + /// G4 User detector initializer + G4VUserDetectorConstruction* detector; + /// Initializing Constructor + Geant4DetectorConstructionContext(Geometry::LCDD& l, + G4VUserDetectorConstruction* d) + : lcdd(l), world(0), geometry(0), detector(d) { } + /// Default destructor + ~Geant4DetectorConstructionContext() { } + /// Helper: Assign sensitive detector to logical volume + void setSensitiveDetector(G4LogicalVolume* vol, G4VSensitiveDetector* sd); + }; - /// Class to create Geant4 detector geometry from TGeo representation in memory + /// Basic implementation of the Geant4 detector construction action. /** - * On demand (ie. when calling "Construct") the DD4hep geometry is converted - * to Geant4 with all volumes, assemblies, shapes, materials etc. - * The actuak work is performed by the Geant4Converter class called by this method. + * Concrete implementation of the Geant4 detector construction action. + * The sequences as the object's master dispatches the callbacks for + * the "constructGeo()" method to create a detector geometry and the + * "constructSensitives()" call to create the sensitive detectors + * and the "constructField" to each worker subclassing + * Geant4DetectorConstruction. + * + * Please note: + * constructField() and constructSensitives() are executed in a + * thread-local context. See the Geant4 documentation for details: + * https://twiki.cern.ch/twiki/bin/view/Geant4/QuickMigrationGuideForGeant4V10 * * \author M.Frank * \version 1.0 * \ingroup DD4HEP_SIMULATION */ - class Geant4DetectorConstruction : public Geant4Action, public G4VUserDetectorConstruction { + class Geant4DetectorConstruction : public Geant4Action { public: - /// Instance accessor - static Geant4DetectorConstruction* instance(Geant4Kernel& kernel); - /// Initializing constructor for DDG4 - Geant4DetectorConstruction(Geant4Kernel& kernel); - /// Initializing constructor for other clients - Geant4DetectorConstruction(Geometry::LCDD& lcdd); + /// Standard Constructor + Geant4DetectorConstruction(Geant4Context* context, const std::string& nam); /// Default destructor virtual ~Geant4DetectorConstruction(); - /// Geometry construction callback: Invoke the conversion to Geant4 - G4VPhysicalVolume* Construct(); + /// Geometry construction callback. Called at "Construct()" + virtual void constructGeo(Geant4DetectorConstructionContext* ctxt); + /// Electromagnetic field construction callback. Called at "ConstructSDandField()" + virtual void constructField(Geant4DetectorConstructionContext* ctxt); + /// Sensitive detector construction callback. Called at "ConstructSDandField()" + virtual void constructSensitives(Geant4DetectorConstructionContext* ctxt); + }; + + /// Concrete basic implementation of the Geant4 detector construction sequencer. + /** + * Concrete implementation of the Geant4 detector construction sequence. + * The sequence dispatches the callbacks for the "Construct()" method to + * create a detector geometry and to dispatch the "ConstructSDandField()" + * calls for each worker. + * + * Please note: + * constructField() and constructSensitives() are executed in a + * thread-local context. See the Geant4 documentation for details: + * https://twiki.cern.ch/twiki/bin/view/Geant4/QuickMigrationGuideForGeant4V10 + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4DetectorConstructionSequence : public Geant4Action { + protected: + /// The list of action objects to be called + Actors<Geant4DetectorConstruction> m_actors; + + public: + /// Standard Constructor + Geant4DetectorConstructionSequence(Geant4Context* context, const std::string& nam); + /// Default destructor + virtual ~Geant4DetectorConstructionSequence(); + /// Set or update client context + virtual void updateContext(Geant4Context* ctxt); + /// Add an actor responding to all callbacks. Sequence takes ownership. + void adopt(Geant4DetectorConstruction* action); + /// Geometry construction callback. Called at "Construct()" + virtual void constructGeo(Geant4DetectorConstructionContext* ctxt); + /// Electromagnetic field construction callback. Called at "ConstructSDandField()" + virtual void constructField(Geant4DetectorConstructionContext* ctxt); + /// Sensitive detector construction callback. Called at "ConstructSDandField()" + virtual void constructSensitives(Geant4DetectorConstructionContext* ctxt); //@{ Accessor to the various geant4 maps after construction @@ -80,19 +162,12 @@ namespace DD4hep { /// Access to the converted regions const Geant4GeometryMaps::RegionMap& regions() const; /// Access to the converted sensitive detectors - const Geant4GeometryMaps::SensDetMap& sensitives() const; + //const Geant4GeometryMaps::SensDetMap& sensitives() const; //@} - - private: - /// Printlevel used for the geometry conversion - PrintLevel m_outputLevel; - /// Reference to geometry object - Geometry::LCDD& m_lcdd; - /// Reference to the world after construction - G4VPhysicalVolume* m_world; }; - } -} -#endif + } // End namespace Simulation +} // End namespace DD4hep + +#endif // DD4HEP_DDG4_GEANT4DETECTORCONSTRUCTION_H diff --git a/DDG4/include/DDG4/Geant4EventAction.h b/DDG4/include/DDG4/Geant4EventAction.h index 4cb74040ee4a5939290aae4f834c926a3ff0f48e..f6fe64b9f34e0318932c81daa4a7186de6eadfc7 100644 --- a/DDG4/include/DDG4/Geant4EventAction.h +++ b/DDG4/include/DDG4/Geant4EventAction.h @@ -27,6 +27,11 @@ namespace DD4hep { /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit namespace Simulation { + // Forward declarations + class Geant4EventAction; + class Geant4SharedEventAction; + class Geant4EventActionSequence; + /// Concrete basic implementation of the Geant4 event action /** * The EventAction is called for every event. @@ -47,6 +52,8 @@ namespace DD4hep { * \ingroup DD4HEP_SIMULATION */ class Geant4EventAction : public Geant4Action { + public: + typedef Geant4SharedEventAction shared_type; public: /// Standard constructor Geant4EventAction(Geant4Context* context, const std::string& nam); @@ -58,12 +65,49 @@ namespace DD4hep { virtual void end(const G4Event* event); }; + /// Implementation of the Geant4 shared event action + /** + * Wrapper to share single instances of event actions for + * multi-threaded purposes. The wrapper ensures the locking + * of the basic actions to avoid race conditions. + * + * Shared action should be 'fast'. The global lock otherwise + * inhibits the efficient use of the multiple threads. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4SharedEventAction : public Geant4EventAction { + protected: + /// Reference to the shared action + Geant4EventAction* m_action; + public: + /// Standard constructor + Geant4SharedEventAction(Geant4Context* context, const std::string& nam); + /// Default destructor + virtual ~Geant4SharedEventAction(); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); + /// Underlying object to be used during the execution of this thread + virtual void use(Geant4EventAction* action); + /// Begin-of-event callback + virtual void begin(const G4Event* event); + /// End-of-event callback + virtual void end(const G4Event* event); + }; + /// Concrete implementation of the Geant4 event action sequence /** * The sequence dispatches the callbacks at the beginning and the and * of an event to all registered Geant4EventAction members and all * registered callbacks. * + * Note Multi-Threading issue: + * Neither callbacks not the action list is protected against multiple + * threads calling the Geant4 callbacks! + * These must be protected in the user actions themselves. + * * \author M.Frank * \version 1.0 * \ingroup DD4HEP_SIMULATION @@ -83,6 +127,12 @@ namespace DD4hep { Geant4EventActionSequence(Geant4Context* context, const std::string& nam); /// Default destructor virtual ~Geant4EventActionSequence(); + /// Set or update client context + virtual void updateContext(Geant4Context* ctxt); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); + /// Get an action by name + Geant4EventAction* get(const std::string& name) const; /// Register begin-of-event callback template <typename Q, typename T> void callAtBegin(Q* p, void (T::*f)(const G4Event*)) { diff --git a/DDG4/include/DDG4/Geant4GeneratorAction.h b/DDG4/include/DDG4/Geant4GeneratorAction.h index dc44809a1aefdac2d0ca606041ee160b7650f1fe..354c52d4199178f3502ab5636f1bf45aef3d9690 100644 --- a/DDG4/include/DDG4/Geant4GeneratorAction.h +++ b/DDG4/include/DDG4/Geant4GeneratorAction.h @@ -26,6 +26,11 @@ namespace DD4hep { /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit namespace Simulation { + // Forward declarations + class Geant4GeneratorAction; + class Geant4SharedGeneratorAction; + class Geant4GeneratorActionSequence; + /// Concrete implementation of the Geant4 generator action base class /** * The Geant4GeneratorAction is called for every event. @@ -41,6 +46,8 @@ namespace DD4hep { * \ingroup DD4HEP_SIMULATION */ class Geant4GeneratorAction : public Geant4Action { + public: + typedef Geant4SharedGeneratorAction shared_type; protected: Callback m_calls; public: @@ -53,6 +60,36 @@ namespace DD4hep { } }; + /// Implementation of the Geant4 shared generator action + /** + * Wrapper to share single instances of generator actions for + * multi-threaded purposes. The wrapper ensures the locking + * of the basic actions to avoid race conditions. + * + * Shared action should be 'fast'. The global lock otherwise + * inhibits the efficient use of the multiple threads. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4SharedGeneratorAction : public Geant4GeneratorAction { + protected: + /// Reference to the shared action + Geant4GeneratorAction* m_action; + public: + /// Standard constructor + Geant4SharedGeneratorAction(Geant4Context* context, const std::string& nam); + /// Default destructor + virtual ~Geant4SharedGeneratorAction(); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); + /// Underlying object to be used during the execution of this thread + virtual void use(Geant4GeneratorAction* action); + /// User generator callback + virtual void operator()(G4Event* event); + }; + /// Concrete implementation of the Geant4 generator action sequence /** * The sequence dispatches the callbacks at the beginning @@ -61,6 +98,11 @@ namespace DD4hep { * * The callback signature is: void operator()(G4Event* event) * + * Note Multi-Threading issue: + * Neither callbacks not the action list is protected against multiple + * threads calling the Geant4 callbacks! + * These must be protected in the user actions themselves. + * * \author M.Frank * \version 1.0 * \ingroup DD4HEP_SIMULATION @@ -76,6 +118,12 @@ namespace DD4hep { Geant4GeneratorActionSequence(Geant4Context* context, const std::string& name); /// Default destructor virtual ~Geant4GeneratorActionSequence(); + /// Set or update client context + virtual void updateContext(Geant4Context* ctxt); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); + /// Get an action by name + Geant4GeneratorAction* get(const std::string& name) const; /// Register primary particle generation callback. Types Q and T must be polymorph! template <typename Q, typename T> void call(Q* p, void (T::*f)(G4Event*)) { diff --git a/DDG4/include/DDG4/Geant4GeometryInfo.h b/DDG4/include/DDG4/Geant4GeometryInfo.h index 860b5f1d78fecf4e9d003c5f7448e54ec894ef3e..3b66db96c4d9c75167036796d1679e031d586f31 100644 --- a/DDG4/include/DDG4/Geant4GeometryInfo.h +++ b/DDG4/include/DDG4/Geant4GeometryInfo.h @@ -74,7 +74,6 @@ namespace DD4hep { typedef std::map<LimitSet, G4UserLimits*> LimitMap; typedef std::map<PlacedVolume, G4VPhysicalVolume*> PlacementMap; typedef std::map<Region, G4Region*> RegionMap; - typedef std::map<SensitiveDetector, G4VSensitiveDetector*> SensDetMap; typedef std::map<Volume, G4LogicalVolume*> VolumeMap; typedef std::map<PlacedVolume, Geant4AssemblyVolume*> AssemblyMap; @@ -111,10 +110,7 @@ namespace DD4hep { Geant4GeometryMaps::RegionMap g4Regions; Geant4GeometryMaps::VisMap g4Vis; Geant4GeometryMaps::LimitMap g4Limits; - Geant4GeometryMaps::SensDetMap g4SensDets; - Geant4GeometryMaps::Geant4PathMap g4Paths; - Geant4GeometryMaps::SensitiveVolumes sensitives; Geant4GeometryMaps::RegionVolumes regions; Geant4GeometryMaps::LimitVolumes limits; diff --git a/DDG4/include/DDG4/Geant4Handle.h b/DDG4/include/DDG4/Geant4Handle.h index 53ec8d8135465ccacd7b379a1ef5e8fac507dfb2..fba05d189bf43a43278df9f4bb7d04670e64bd24 100644 --- a/DDG4/include/DDG4/Geant4Handle.h +++ b/DDG4/include/DDG4/Geant4Handle.h @@ -44,28 +44,45 @@ namespace DD4hep { void checked_assign(TYPE* p); public: typedef TYPE handled_type; + /// Pointer to referenced object mutable handled_type* value; + /// Default constructor explicit Geant4Handle(); + /// Construction initialized with object pointer Geant4Handle(handled_type* typ); + /// Cross type initialization template <typename T> Geant4Handle(T* typ) : value(0) { checked_assign(dynamic_cast<handled_type*>(typ)); } + /// Copy constructor Geant4Handle(const Geant4Handle& handle); - Geant4Handle(Geant4Kernel&, const char* type_name); - Geant4Handle(Geant4Kernel&, const std::string& type_name); + /// Initializing constructor + Geant4Handle(Geant4Kernel&, const char* type_name, bool shared=false); + /// Initializing constructor + Geant4Handle(Geant4Kernel&, const std::string& type_name, bool shared=false); /// Constructor only implemented for sensitive objects - Geant4Handle(Geant4Kernel& ctxt, const std::string& type_name, const std::string& detector); + Geant4Handle(Geant4Kernel& ctxt, const std::string& type_name, const std::string& detector, bool shared=false); + /// Default destructor ~Geant4Handle(); + /// Property accessor Property& operator[](const std::string& property_name) const; + /// Assignment operator Geant4Handle& operator=(const Geant4Handle& handle); + /// Assignment operator Geant4Handle& operator=(handled_type* ptr); + /// Validity check bool operator!() const; + /// Access to the underlying object + Geant4Action* action() const; + /// Access to the underlying object + handled_type* operator->() const; + /// Conversion operator operator handled_type*() const; + /// Access to the underlying object handled_type* get() const; + /// Release the underlying object handled_type* release(); - handled_type* operator->() const; - Geant4Action* action() const; }; /// Handle to Geant4 actions with built-in creation mechanism @@ -77,12 +94,25 @@ namespace DD4hep { class KernelHandle { public: typedef Geant4Kernel handled_type; + /// Pointer to referenced object mutable handled_type* value; + /// Default constructor explicit KernelHandle(); + /// Construction initialized with object pointer + explicit KernelHandle(Geant4Kernel* k); + /// Copy constructor + KernelHandle(const KernelHandle& k) : value(k.value) {} + /// Default destructor ~KernelHandle() {} + /// Conversion operator operator handled_type*() const { return value; } + /// Access to the underlying object handled_type* get() const { return value; } + /// Access to the underlying object handled_type* operator->() const { return value; } + /// Access to worker thread + KernelHandle worker(); + /// Destroy referenced object (program termination) void destroy(); }; diff --git a/DDG4/include/DDG4/Geant4Kernel.h b/DDG4/include/DDG4/Geant4Kernel.h index b2e7832edb176679908afd2fd34130bb0eba4976..5dd89f2490ee7754f57ba785c5ee006e3ee018ef 100644 --- a/DDG4/include/DDG4/Geant4Kernel.h +++ b/DDG4/include/DDG4/Geant4Kernel.h @@ -19,10 +19,14 @@ #include "DDG4/Geant4Primitives.h" #include "DDG4/Geant4Action.h" +// Geant4 headers +#include "G4Threading.hh" + // C/C++ include files #include <map> #include <string> #include <typeinfo> +#include <pthread.h> // Forward declarations class G4RunManager; @@ -52,6 +56,8 @@ namespace DD4hep { class Geant4StackingActionSequence; class Geant4GeneratorActionSequence; class Geant4PhysicsListActionSequence; + class Geant4DetectorConstructionSequence; + class Geant4UserInitializationSequence; class Geant4SensDetActionSequence; class Geant4SensDetSequences; @@ -64,6 +70,7 @@ namespace DD4hep { class Geant4Kernel { public: typedef DD4hep::Geometry::LCDD LCDD; + typedef std::map<unsigned long, Geant4Kernel*> Workers; typedef std::map<std::string, Geant4ActionPhase*> Phases; typedef std::map<std::string, Geant4Action*> GlobalActions; @@ -71,30 +78,38 @@ namespace DD4hep { /// Reference to the run manager G4RunManager* m_runManager; /// Top level control directory - G4UIdirectory* m_control; + G4UIdirectory* m_control; /// Property pool - PropertyManager m_properties; + PropertyManager m_properties; /// Reference to the Geant4 primary generator action - Geant4GeneratorActionSequence* m_generatorAction; + Geant4GeneratorActionSequence* m_generatorAction; /// Reference to the Geant4 run action - Geant4RunActionSequence* m_runAction; + Geant4RunActionSequence* m_runAction; /// Reference to the Geant4 event action - Geant4EventActionSequence* m_eventAction; + Geant4EventActionSequence* m_eventAction; /// Reference to the Geant4 track action - Geant4TrackingActionSequence* m_trackingAction; + Geant4TrackingActionSequence* m_trackingAction; /// Reference to the Geant4 step action - Geant4SteppingActionSequence* m_steppingAction; + Geant4SteppingActionSequence* m_steppingAction; /// Reference to the Geant4 stacking action - Geant4StackingActionSequence* m_stackingAction; + Geant4StackingActionSequence* m_stackingAction; + /// Reference to the Geant4 detector construction sequence + Geant4DetectorConstructionSequence* m_constructionAction; + /// Reference to the Geant4 sensitive action sequences - Geant4SensDetSequences* m_sensDetActions; - /// Reference to the geant4 physics list - Geant4PhysicsListActionSequence* m_physicsList; + Geant4SensDetSequences* m_sensDetActions; + /// Reference to the Geant4 physics list + Geant4PhysicsListActionSequence* m_physicsList; + /// Reference to the user initialization object + Geant4UserInitializationSequence* m_userInit; + /// Reference to Geant4 track manager G4TrackingManager* m_trackMgr; /// Action phases - Phases m_phases; + Phases m_phases; + /// Worker threads + Workers m_workers; /// Globally registered actions GlobalActions m_globalActions; /// Globally registered filters of sensitive detectors @@ -112,12 +127,40 @@ namespace DD4hep { /// Property: Client output levels typedef std::map<std::string,int> ClientOutputLevels; ClientOutputLevels m_clientLevels; + + /// Property: Running in multi threaded context + //bool m_multiThreaded; + /// Master property: Number of execution threads in multi threaded mode. + int m_numThreads; + /// Flag: Master instance (id<0) or worker (id >= 0) + unsigned long m_id, m_ident; + /// Parent reference + Geant4Kernel* m_master; + Geant4Context* m_threadContext; + + bool isMaster() const { return this == m_master; } + bool isWorker() const { return this != m_master; } + /// Helper to register an action sequence template <typename C> bool registerSequence(C*& seq, const std::string& name); +#ifndef __CINT__ + /// Standard constructor for workers + Geant4Kernel(LCDD& lcdd, Geant4Kernel* m, unsigned long identifier); +#endif + public: - /// Standard constructor + /// Standard constructor for the master instance Geant4Kernel(LCDD& lcdd); + + /// Thread's master context + Geant4Context* workerContext(); + + /// Thread's master context + Geant4Kernel& master() const { return *m_master; } + + //bool isMultiThreaded() const { return m_multiThreaded; } + bool isMultiThreaded() const { return m_numThreads > 0; } public: /// Embedded helper class to facilitate map access to the phases. @@ -145,6 +188,7 @@ namespace DD4hep { }; /// Default destructor virtual ~Geant4Kernel(); + #ifndef __CINT__ /// Instance accessor static Geant4Kernel& instance(LCDD& lcdd); @@ -173,12 +217,16 @@ namespace DD4hep { void setTrackMgr(G4TrackingManager* mgr) { m_trackMgr = mgr; } - /// Access to the Geant4 run manager - G4RunManager& runManager(); /// Access the command directory const std::string& directoryName() const { return m_controlName; } + /// Access worker identifier + unsigned long id() const { + return m_ident; + } + /// Access to the Geant4 run manager + G4RunManager& runManager(); /// Declare property template <typename T> Geant4Kernel& declareProperty(const std::string& nam, T& val); /// Declare property @@ -288,6 +336,13 @@ namespace DD4hep { return *stackingAction(true); } + /// Access detector construcion action sequence (geometry+sensitives+field) + Geant4DetectorConstructionSequence* detectorConstruction(bool create); + /// Access detector construcion action sequence (geometry+sensitives+field) + Geant4DetectorConstructionSequence& detectorConstruction() { + return *detectorConstruction(true); + } + /// Access to the sensitive detector sequences from the kernel object Geant4SensDetSequences& sensitiveActions() const; /// Access to the sensitive detector action from the kernel object @@ -299,19 +354,33 @@ namespace DD4hep { Geant4PhysicsListActionSequence& physicsList() { return *physicsList(true); } + /// Access to the user initialization object + Geant4UserInitializationSequence* userInitialization(bool create); + /// Access to the user initialization object + Geant4UserInitializationSequence& userInitialization() { + return *userInitialization(true); + } /// Construct detector geometry using lcdd plugin void loadGeometry(const std::string& compact_file); + /** Geant4 Multi threading support */ + /// Create identified worker instance + Geant4Kernel& createWorker(); + /// Access worker instance by it's identifier + Geant4Kernel& worker(unsigned long thread_identifier); + /// Access number of workers + int numWorkers() const; + /// Run the simulation: Configure Geant4 - void configure(); + int configure(); /// Run the simulation: Initialize Geant4 - void initialize(); + int initialize(); /// Run the simulation: Simulate the number of events given by the property "NumEvents" - void run(); + int run(); /// Run the simulation: Simulate the number of events "num_events" and modify the property "NumEvents" - void runEvents(int num_events); + int runEvents(int num_events); /// Run the simulation: Terminate Geant4 - void terminate(); + int terminate(); /// Load XML file void loadXML(const char* fname); }; diff --git a/DDG4/include/DDG4/Geant4OutputAction.h b/DDG4/include/DDG4/Geant4OutputAction.h index 4d19c8f30e89ce25e663ff43409931692aea8c18..b7ebfdbb3fee94f2a85d726a7d0202a618919051 100644 --- a/DDG4/include/DDG4/Geant4OutputAction.h +++ b/DDG4/include/DDG4/Geant4OutputAction.h @@ -64,6 +64,8 @@ namespace DD4hep { Geant4OutputAction(Geant4Context* c, const std::string& nam); /// Default destructor virtual ~Geant4OutputAction(); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* ctxt); /// begin-of-event callback virtual void begin(const G4Event* event); diff --git a/DDG4/include/DDG4/Geant4ParticleHandler.h b/DDG4/include/DDG4/Geant4ParticleHandler.h index a129a7f4d28a432509a90df1f2bcb61ec10920d4..e18be8ef979fb1bfb178069986d881995e6d0f40 100644 --- a/DDG4/include/DDG4/Geant4ParticleHandler.h +++ b/DDG4/include/DDG4/Geant4ParticleHandler.h @@ -80,6 +80,7 @@ namespace DD4hep { protected: + /** Property variables used to configure the object */ /// Property: Steer printout at tracking action begin bool m_printStartTracking; /// Property: Steer printout at tracking action end @@ -90,21 +91,24 @@ namespace DD4hep { bool m_ownsParticles; /// Property: Energy cut below which particles are not collected, but assigned to the parent double m_kinEnergyCut; + /// Property: All the processes of which the decay products will be explicitly stored + Processes m_processNames; - /// Global particle identifier. Obtained at the begin of the event. - int m_globalParticleID; + /** Object variables, which are constant after initialization */ /// User action pointer Geant4UserParticleHandler* m_userHandler; + + /** EVENT DEPENDENT: variables containing data depending on the current event. */ + /// Global particle identifier. Obtained at the begin of the event. + int m_globalParticleID; /// Primary map Geant4PrimaryMap* m_primaryMap; /// Local buffer about the 'current' G4Track - Particle m_currTrack; + Particle m_currTrack; /// Map with stored MC Particles - ParticleMap m_particleMap; + ParticleMap m_particleMap; /// Map associating the G4Track identifiers with identifiers of existing MCParticles - TrackEquivalents m_equivalentTracks; - /// All the processes of which the decay products will be explicitly stored - Processes m_processNames; + TrackEquivalents m_equivalentTracks; /// Recombine particles and associate the to parents with cleanup int recombineParents(); diff --git a/DDG4/include/DDG4/Geant4RunAction.h b/DDG4/include/DDG4/Geant4RunAction.h index ed065e532b53b5284bdb2fc3d5a2530014e47e58..4d14b02fa419448b0cdc5375a6b7627533657135 100644 --- a/DDG4/include/DDG4/Geant4RunAction.h +++ b/DDG4/include/DDG4/Geant4RunAction.h @@ -27,6 +27,11 @@ namespace DD4hep { /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit namespace Simulation { + // Forward declarations + class Geant4RunAction; + class Geant4SharedRunAction; + class Geant4RunActionSequence; + /// Concrete basic implementation of the Geant4 run action base class. /** * The Run Action is called once per start and end of a run. @@ -39,6 +44,8 @@ namespace DD4hep { * \ingroup DD4HEP_SIMULATION */ class Geant4RunAction: public Geant4Action { + public: + typedef Geant4SharedRunAction shared_type; public: /// Standard constructor Geant4RunAction(Geant4Context* context, const std::string& nam); @@ -50,6 +57,38 @@ namespace DD4hep { virtual void end(const G4Run* run); }; + /// Implementation of the Geant4 shared run action + /** + * Wrapper to share single instances of run actions for + * multi-threaded purposes. The wrapper ensures the locking + * of the basic actions to avoid race conditions. + * + * Shared action should be 'fast'. The global lock otherwise + * inhibits the efficient use of the multiple threads. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4SharedRunAction : public Geant4RunAction { + protected: + /// Reference to the shared action + Geant4RunAction* m_action; + public: + /// Standard constructor + Geant4SharedRunAction(Geant4Context* context, const std::string& nam); + /// Default destructor + virtual ~Geant4SharedRunAction(); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); + /// Underlying object to be used during the execution of this thread + virtual void use(Geant4RunAction* action); + /// Begin-of-run callback + virtual void begin(const G4Run* run); + /// End-of-run callback + virtual void end(const G4Run* run); + }; + /// Concrete basic implementation of the Geant4 run action sequencer. /** * Concrete implementation of the Geant4 run action sequence. @@ -57,6 +96,10 @@ namespace DD4hep { * of a run to all registered Geant4RunAction members and all * registered callbacks. * + * Note Multi-Threading issue: + * Callbacks and the action list is protected against multiple + * threads calling the Geant4 callbacks! + * * \author M.Frank * \version 1.0 * \ingroup DD4HEP_SIMULATION @@ -74,6 +117,12 @@ namespace DD4hep { Geant4RunActionSequence(Geant4Context* context, const std::string& nam); /// Default destructor virtual ~Geant4RunActionSequence(); + /// Set or update client context + virtual void updateContext(Geant4Context* ctxt); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); + /// Get an action by name + Geant4RunAction* get(const std::string& name) const; /// Register begin-of-run callback. Types Q and T must be polymorph! template <typename Q, typename T> void callAtBegin(Q* p, void (T::*f)(const G4Run*)) { diff --git a/DDG4/include/DDG4/Geant4SensDetAction.h b/DDG4/include/DDG4/Geant4SensDetAction.h index 91c0faff285d8e3dbc6d2638e70eb9e6a20a6bf4..c6bba449929f7c55b7321b4212fbbe6c17f38002 100644 --- a/DDG4/include/DDG4/Geant4SensDetAction.h +++ b/DDG4/include/DDG4/Geant4SensDetAction.h @@ -319,6 +319,9 @@ namespace DD4hep { return m_sensitiveType; } + /// Set or update client context + virtual void updateContext(Geant4Context* ctxt); + /// Called at construction time of the sensitive detector to declare all hit collections size_t defineCollections(Geant4ActionSD* sens_det); @@ -395,6 +398,11 @@ namespace DD4hep { /** * Concrete implementation of the sensitive detector action sequence * + * Note Multi-Threading issue: + * Neither callbacks not the action list is protected against multiple + * threads calling the Geant4 callbacks! + * These must be protected in the user actions themselves. + * * \author M.Frank * \version 1.0 * \ingroup DD4HEP_SIMULATION @@ -442,7 +450,7 @@ namespace DD4hep { * * Users may override any of the templated callbacks or the of the virtual functions * of the base class using explicit template specialization. - * An example may be found in DDG4/plugins/eant4SDActions. + * An example may be found in DDG4/plugins/Geant4SDActions. * * \author M.Frank * \version 1.0 @@ -453,9 +461,10 @@ namespace DD4hep { typedef T UserData; protected: /// Collection identifier - size_t m_collectionID; + size_t m_collectionID; /// User data block - UserData m_userData; + UserData m_userData; + public: /// Standard , initializing constructor Geant4SensitiveAction(Geant4Context* context, @@ -465,9 +474,9 @@ namespace DD4hep { /// Default destructor virtual ~Geant4SensitiveAction(); /// Initialization overload for specialization - void initialize(); + virtual void initialize(); /// Finalization overload for specialization - void finalize(); + virtual void finalize(); /// Define collections created by this sensitivie action object virtual void defineCollections() {} /// G4VSensitiveDetector interface: Method invoked at the begining of each event. diff --git a/DDG4/include/DDG4/Geant4StackingAction.h b/DDG4/include/DDG4/Geant4StackingAction.h index 4c05ffe5d102cd716a9553b57074203c6e5b764c..95e492840ceac333688185b554c58ebaa0c43cb3 100644 --- a/DDG4/include/DDG4/Geant4StackingAction.h +++ b/DDG4/include/DDG4/Geant4StackingAction.h @@ -23,6 +23,11 @@ namespace DD4hep { /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit namespace Simulation { + // Forward declarations + class Geant4StackingAction; + class Geant4SharedStackingAction; + class Geant4StackingActionSequence; + /// Concrete implementation of the Geant4 stacking action base class /** * \author M.Frank @@ -30,6 +35,8 @@ namespace DD4hep { * \ingroup DD4HEP_SIMULATION */ class Geant4StackingAction: public Geant4Action { + public: + typedef Geant4SharedStackingAction shared_type; public: /// Standard constructor Geant4StackingAction(Geant4Context* ctxt, const std::string& name); @@ -43,12 +50,49 @@ namespace DD4hep { } }; + /// Implementation of the Geant4 shared stacking action + /** + * Wrapper to share single instances of stacking actions for + * multi-threaded purposes. The wrapper ensures the locking + * of the basic actions to avoid race conditions. + * + * Shared action should be 'fast'. The global lock otherwise + * inhibits the efficient use of the multiple threads. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4SharedStackingAction : public Geant4StackingAction { + protected: + /// Reference to the shared action + Geant4StackingAction* m_action; + public: + /// Standard constructor + Geant4SharedStackingAction(Geant4Context* context, const std::string& nam); + /// Default destructor + virtual ~Geant4SharedStackingAction(); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); + /// Underlying object to be used during the execution of this thread + virtual void use(Geant4StackingAction* action); + /// New-stage callback + virtual void newStage(); + /// Preparation callback + virtual void prepare(); + }; + /// Concrete implementation of the Geant4 stacking action sequence /** * The sequence dispatches the callbacks for each stepping action * to all registered Geant4StackingAction members and all * registered callbacks. * + * Note Multi-Threading issue: + * Neither callbacks not the action list is protected against multiple + * threads calling the Geant4 callbacks! + * These must be protected in the user actions themselves. + * * \author M.Frank * \version 1.0 * \ingroup DD4HEP_SIMULATION @@ -66,6 +110,12 @@ namespace DD4hep { Geant4StackingActionSequence(Geant4Context* ctxt, const std::string& name); /// Default destructor virtual ~Geant4StackingActionSequence(); + /// Set or update client context + virtual void updateContext(Geant4Context* ctxt); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); + /// Get an action by name + Geant4StackingAction* get(const std::string& name) const; /// Register begin-of-event callback. Types Q and T must be polymorph! template <typename T> void callAtNewStage(T* p, void (T::*f)()) { m_newStage.add(p, f); diff --git a/DDG4/include/DDG4/Geant4SteppingAction.h b/DDG4/include/DDG4/Geant4SteppingAction.h index 39a8fcc1381029575431476e10c7db217c34138b..b1d2087a39ebb02606329331e768ce312383c401 100644 --- a/DDG4/include/DDG4/Geant4SteppingAction.h +++ b/DDG4/include/DDG4/Geant4SteppingAction.h @@ -27,6 +27,11 @@ namespace DD4hep { /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit namespace Simulation { + // Forward declarations + class Geant4SteppingAction; + class Geant4SharedSteppingAction; + class Geant4SteppingActionSequence; + /// Concrete implementation of the Geant4 stepping action sequence /** * \author M.Frank @@ -34,6 +39,8 @@ namespace DD4hep { * \ingroup DD4HEP_SIMULATION */ class Geant4SteppingAction: public Geant4Action { + public: + typedef Geant4SharedSteppingAction shared_type; public: /// Standard constructor Geant4SteppingAction(Geant4Context* context, const std::string& name); @@ -43,12 +50,47 @@ namespace DD4hep { virtual void operator()(const G4Step* step, G4SteppingManager* mgr); }; + /// Implementation of the Geant4 shared stepping action + /** + * Wrapper to share single instances of stepping actions for + * multi-threaded purposes. The wrapper ensures the locking + * of the basic actions to avoid race conditions. + * + * Shared action should be 'fast'. The global lock otherwise + * inhibits the efficient use of the multiple threads. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4SharedSteppingAction : public Geant4SteppingAction { + protected: + /// Reference to the shared action + Geant4SteppingAction* m_action; + public: + /// Standard constructor + Geant4SharedSteppingAction(Geant4Context* context, const std::string& nam); + /// Default destructor + virtual ~Geant4SharedSteppingAction(); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); + /// Underlying object to be used during the execution of this thread + virtual void use(Geant4SteppingAction* action); + /// User stepping callback + virtual void operator()(const G4Step* step, G4SteppingManager* mgr); + }; + /// Concrete implementation of the Geant4 stepping action sequence /** * The sequence dispatches the callbacks for each stepping action * to all registered Geant4SteppingAction members and all * registered callbacks. * + * Note Multi-Threading issue: + * Neither callbacks not the action list is protected against multiple + * threads calling the Geant4 callbacks! + * These must be protected in the user actions themselves. + * * \author M.Frank * \version 1.0 * \ingroup DD4HEP_SIMULATION @@ -65,6 +107,12 @@ namespace DD4hep { Geant4SteppingActionSequence(Geant4Context* context, const std::string& name); /// Default destructor virtual ~Geant4SteppingActionSequence(); + /// Set or update client context + virtual void updateContext(Geant4Context* ctxt); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); + /// Get an action by name + Geant4SteppingAction* get(const std::string& name) const; /// Register stepping action callback. Types Q and T must be polymorph! template <typename Q, typename T> void call(Q* p, void (T::*f)(const G4Step*, G4SteppingManager*)) { diff --git a/DDG4/include/DDG4/Geant4TrackingAction.h b/DDG4/include/DDG4/Geant4TrackingAction.h index 23390de42df6dcab1358db2be8ec80cf3e85f1c1..2537b33da62f881869388f0922c8e532ddf4f9c2 100644 --- a/DDG4/include/DDG4/Geant4TrackingAction.h +++ b/DDG4/include/DDG4/Geant4TrackingAction.h @@ -29,6 +29,9 @@ namespace DD4hep { // Forward declarations class Geant4TrackInformation; + class Geant4TrackingAction; + class Geant4SharedTrackingAction; + class Geant4TrackingActionSequence; /// Default base class for all geant 4 tracking actions used in DDG4. /** @@ -37,6 +40,8 @@ namespace DD4hep { * \ingroup DD4HEP_SIMULATION */ class Geant4TrackingAction: public Geant4Action { + public: + typedef Geant4SharedTrackingAction shared_type; public: /// Standard constructor Geant4TrackingAction(Geant4Context* context, const std::string& name = ""); @@ -44,28 +49,59 @@ namespace DD4hep { virtual ~Geant4TrackingAction(); /// Access the Geant4 tracking manager. Only use between tracking pre- and post action G4TrackingManager* trackMgr() const { - return m_context.trackMgr(); + return m_context ? m_context->trackMgr() : 0; } /// Mark the track to be kept for MC truth propagation void mark(const G4Track* track) const; - /// Get the valid Geant4 tarck information - Geant4TrackInformation* trackInfo(G4Track* track) const; - /// Mark all children of the track to be stored - bool storeChildren() const; - /// Mark a single child of the track to be stored - bool storeChild(Geant4TrackInformation* info) const; /// Pre-track action callback virtual void begin(const G4Track* track); /// Post-track action callback virtual void end(const G4Track* track); }; + /// Implementation of the Geant4 shared track action + /** + * Wrapper to share single instances of track actions for + * multi-threaded purposes. The wrapper ensures the locking + * of the basic actions to avoid race conditions. + * + * Shared action should be 'fast'. The global lock otherwise + * inhibits the efficient use of the multiple threads. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4SharedTrackingAction : public Geant4TrackingAction { + protected: + /// Reference to the shared action + Geant4TrackingAction* m_action; + public: + /// Standard constructor + Geant4SharedTrackingAction(Geant4Context* context, const std::string& nam); + /// Default destructor + virtual ~Geant4SharedTrackingAction(); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); + /// Underlying object to be used during the execution of this thread + virtual void use(Geant4TrackingAction* action); + /// Begin-of-track callback + virtual void begin(const G4Track* track); + /// End-of-track callback + virtual void end(const G4Track* track); + }; + /// Concrete implementation of the Geant4 tracking action sequence /** * The sequence dispatches the callbacks for each tracking action * to all registered Geant4SteppingAction members and all * registered callbacks. * + * Note Multi-Threading issue: + * Neither callbacks not the action list is protected against multiple + * threads calling the Geant4 callbacks! + * These must be protected in the user actions themselves. + * * \author M.Frank * \version 1.0 * \ingroup DD4HEP_SIMULATION @@ -87,6 +123,12 @@ namespace DD4hep { Geant4TrackingActionSequence(Geant4Context* context, const std::string& name); /// Default destructor virtual ~Geant4TrackingActionSequence(); + /// Set or update client context + virtual void updateContext(Geant4Context* ctxt); + /// Set or update client for the use in a new thread fiber + virtual void configureFiber(Geant4Context* thread_context); + /// Get an action by name + Geant4TrackingAction* get(const std::string& name) const; /// Register Pre-track action callback before anything else template <typename Q, typename T> void callUpFront(Q* p, void (T::*f)(const G4Track*), diff --git a/DDG4/include/DDG4/Geant4UserInitialization.h b/DDG4/include/DDG4/Geant4UserInitialization.h new file mode 100644 index 0000000000000000000000000000000000000000..0e91f50b4ac2d4897c94e331e63605b3116bc25f --- /dev/null +++ b/DDG4/include/DDG4/Geant4UserInitialization.h @@ -0,0 +1,88 @@ +// $Id$ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DD4HEP_DDG4_GEANT4USERINITIALIZATION_H +#define DD4HEP_DDG4_GEANT4USERINITIALIZATION_H + +// Framework include files +#include "DDG4/Geant4Action.h" + +// Forward declarations + +/// Namespace for the AIDA detector description toolkit +namespace DD4hep { + + /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit + namespace Simulation { + + /// Base class to initialize a multi-threaded or single threaded Geant4 application + /** + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4UserInitialization : public Geant4Action { + protected: + public: + /// Standard constructor + Geant4UserInitialization(Geant4Context* c, const std::string& nam); + /// Default destructor + virtual ~Geant4UserInitialization(); + /// Callback function to build setup for the MT worker thread + virtual void build() const; + /// Callback function to build setup for the MT master thread + virtual void buildMaster() const; + }; + + /// Class to orchestrate a modular initializion of a multi- or single threaded Geant4 application + /** + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4UserInitializationSequence : public Geant4UserInitialization { + protected: + /// Callback sequence to initialize the thread master + CallbackSequence m_masterCalls; + /// Callback sequence to initialize worker elements + CallbackSequence m_workerCalls; + /// The list of action objects to be called + Actors<Geant4UserInitialization> m_actors; + + public: + /// Standard constructor + Geant4UserInitializationSequence(Geant4Context* c, const std::string& nam); + /// Default destructor + virtual ~Geant4UserInitializationSequence(); + /// Register callback to setup worker. Types Q and T must be polymorph! + template <typename Q, typename T> void build(Q* p, void (T::*f)()) { + m_workerCalls.add(p, f); + } + /// Register callback to setup master. Types Q and T must be polymorph! + template <typename Q, typename T> void buildMaster(Q* p, void (T::*f)()) { + m_masterCalls.add(p, f); + } + /// Add an actor responding to all callbacks. Sequence takes ownership. + void adopt(Geant4UserInitialization* action); + + /// Set client context + virtual void updateContext(Geant4Context* ctxt); + /// Callback function to build setup for the MT worker thread + virtual void build() const; + /// Callback function to build setup for the MT master thread + virtual void buildMaster() const; + }; + + } // End namespace Simulation +} // End namespace DD4hep +#endif // DD4HEP_DDG4_GEANT4USERINITIALIZATION_H diff --git a/DDG4/include/DDG4Python/DDPython.h b/DDG4/include/DDG4Python/DDPython.h new file mode 100644 index 0000000000000000000000000000000000000000..1e165431da44003324947a0d007d2de4cd2fe2c2 --- /dev/null +++ b/DDG4/include/DDG4Python/DDPython.h @@ -0,0 +1,97 @@ +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-07 +// +//========================================================================== +// $Id$ +#ifndef DD4HEP_DDG4_DDPYTHON_H +#define DD4HEP_DDG4_DDPYTHON_H 1 + +// C/C++ include files +#include <string> +#include "TPyReturn.h" + +/// Namespace for the AIDA detector description toolkit +namespace DD4hep { + + struct DDPythonGlobalState; + + /** @class DDPython DDPython.h DDG4/DDPython.h */ + class DDPython { + private: + void* context; + /// Standard constructor + DDPython( ); + protected: + static bool isMainThread(); + public: + struct GILState { + int state; + explicit GILState(int); + ~GILState(); + }; + struct BlockThreads { + explicit BlockThreads(int); + ~BlockThreads(); + }; + struct AllowThreads { + explicit AllowThreads(int); + ~AllowThreads(); + }; + + /// Save thread state + static void allowThreads(); + static void restoreThread(); + /// Object instantiator + static DDPython instance(); + static void shutdown(); + static void setMainThread(); + /// Release python object + static void releaseObject(PyObject*& obj); + /// Release python object + static void assignObject(PyObject*& obj, PyObject* new_obj); + + /// Copy constructor + DDPython(const DDPython& ) {} + /// Destructor + ~DDPython( ); + int setArgs(int argc, char** argv) const; + int runFile(const std::string& fname) const; + int execute(const std::string& cmd) const; + int evaluate(const std::string& cmd) const; + + /// Call a python object with argument (typically a dictionary) + /** Note: + * - Typical call from python -> C -> python + * - Errors are printed and then cleared. A return code of NULL is passed + * to the caller in the event of an error condition + * - The returned object is NOT owned by the caller. + * - No GIL state handling by the caller necessary + */ + PyObject* call(PyObject* method, PyObject* args); + /// Call a python object with argument (typically a dictionary). + /** Note: + * - Typical call from C -> python -> C + * - Errors are printed and then cleared. A return code of NULL is passed + * to the caller in the event of an error condition + * - The returned object TPyReturn must be destructed (ie. leave scope) + * BEFORE the GIL is released. + * - The caller MUST ensure the GIL state in case of multi-threading! + */ + TPyReturn callC(PyObject* method, PyObject* args); + /// Invoke command prompt + void prompt() const; + void afterFork() const; + private: + + }; +} + +#endif // DD4HEP_DDG4_DDPYTHON_H diff --git a/DDG4/include/DDG4Python/Geant4PythonAction.h b/DDG4/include/DDG4Python/Geant4PythonAction.h new file mode 100644 index 0000000000000000000000000000000000000000..5649770ad879efc5532ba527de0e47385af84a3c --- /dev/null +++ b/DDG4/include/DDG4Python/Geant4PythonAction.h @@ -0,0 +1,54 @@ +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ +#ifndef DD4HEP_DDG4_GEANT4PYTHONACTION_H +#define DD4HEP_DDG4_GEANT4PYTHONACTION_H + +// Framework include files +#include "DDG4/Geant4Action.h" +#include "TPyReturn.h" + +/// Namespace for the AIDA detector description toolkit +namespace DD4hep { + + /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit + namespace Simulation { + + /// Base class to initialize a multi-threaded or single threaded Geant4 application + /** + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4PythonAction : public Geant4Action { + public: + /// Standard constructor + Geant4PythonAction(Geant4Context* ctx, const std::string& nam); + /// Default destructor + virtual ~Geant4PythonAction() {} + + /** Public class methods */ + /// Execute command in the python interpreter. + static int call(PyObject* method, PyObject* args); + /// Execute command in the python interpreter. + static int exec(const std::string& cmd); + /// Execute command in the python interpreter. + static int eval(const std::string& cmd); + /// Execute command in the python interpreter. + static int runFile(const std::string& cmd); + /// Invoke command prompt + static void prompt(); + }; + } // End namespace Simulation +} // End namespace DD4hep +#endif // DD4HEP_DDG4_GEANT4PYTHONACTION_H diff --git a/DDG4/include/DDG4Python/Geant4PythonCall.h b/DDG4/include/DDG4Python/Geant4PythonCall.h new file mode 100644 index 0000000000000000000000000000000000000000..7fce64f2be2199c8f720f4da162bdcca86afff48 --- /dev/null +++ b/DDG4/include/DDG4Python/Geant4PythonCall.h @@ -0,0 +1,63 @@ +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ +#ifndef DD4HEP_DDG4_GEANT4PYTHONCALL_H +#define DD4HEP_DDG4_GEANT4PYTHONCALL_H + +// ROOT include files +#include "TPyReturn.h" + +/// Namespace for the AIDA detector description toolkit +namespace DD4hep { + + /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit + namespace Simulation { + + /// Base class to initialize a multi-threaded or single threaded Geant4 application + /** + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4PythonCall { + /// Python callable reference + PyObject* m_callable; + /// Python arguments object + PyObject* m_arguments; + + public: + /// Standard constructor + Geant4PythonCall(); + /// Default destructor + virtual ~Geant4PythonCall(); + + /// Check if call is set + bool isValid() const { return m_callable != 0; } + + /// Execute command in the python interpreter. + template <typename RETURN> RETURN execute() const; + + /// Execute command in the python interpreter. + template <typename RETURN> RETURN execute(PyObject* callable) const; + + /// Execute command in the python interpreter. + template <typename RETURN> RETURN execute(PyObject* callable, PyObject* args) const; + + /// Set the callback structures for callbacks with arguments + void set(PyObject* callable, PyObject* args); + /// Set the callback structures for callbacks without arguments + void set(PyObject* callable); + }; + } // End namespace Simulation +} // End namespace DD4hep +#endif // DD4HEP_DDG4_GEANT4PYTHONCALL_H diff --git a/DDG4/include/DDG4Python/Geant4PythonDetectorConstruction.h b/DDG4/include/DDG4Python/Geant4PythonDetectorConstruction.h new file mode 100644 index 0000000000000000000000000000000000000000..832b0427d0906f1d1cef60873258f9ddb204c7e3 --- /dev/null +++ b/DDG4/include/DDG4Python/Geant4PythonDetectorConstruction.h @@ -0,0 +1,95 @@ +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ +#ifndef DD4HEP_DDG4_GEANT4PYTHONDETECTORCONSTRUCTION_H +#define DD4HEP_DDG4_GEANT4PYTHONDETECTORCONSTRUCTION_H + +// Framework include files +#include "DDG4/Geant4DetectorConstruction.h" +#include "DDG4Python/Geant4PythonCall.h" + +/// Namespace for the AIDA detector description toolkit +namespace DD4hep { + + /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit + namespace Simulation { + + /// Base class to initialize a multi-threaded or single threaded Geant4 application + /** + * Geant4PythonDetectorConstruction is the corresponding + * python action to populate the detector construction sequencer. + * and supports three ccallbacks: + * + * // Set the Detector initialization command + * void setConstructGeo(PyObject* callable, PyObject* args); + * // Set the field initialization command + * void setConstructField(PyObject* callable, PyObject* args); + * // Set the sensitive detector initialization command + * void setConstructSensitives(PyObject* callable, PyObject* args); + * + * to be used in python as call sequence within the master thread: + * + * init_seq = self.master().detectorConstruction(True) + * init_action = DetectorConstruction(self.master(),name_type) + * init_action.setConstructGeo(geometry_setup_call, < geometry_args > ) + * init_action.setConstructField(field_setup_call, < field_args > ) + * init_action.setConstructSensitives(sensitives_setup_call, < sensitives_args >) + * init_seq.adopt(init_action) + * + * If any of the three callback is not set, the corresponding actiion is not executed. + * Hereby are geometry_setup_call, field_setup_call and sensitives\_setup\_call + * the callable objects to configure the geometry, the tracking field + * and the sensitive detectors. + * < geometry_args >, < field_args > and < sensitives\_args > are + * the corresponding callable arguments in the form of a python tuple object. + * + * All python callbacks are supposed to return the integer '1' on success. + * Any other return code is assumed to be failure. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4PythonDetectorConstruction : public Geant4DetectorConstruction { + protected: + /// Sensitive detector initialization command. Default: empty + Geant4PythonCall m_constructSD; + /// Field initialization command. Default: empty + Geant4PythonCall m_constructFLD; + /// Geometry initialization command. Default: empty + Geant4PythonCall m_constructGEO; + /// Execute command in the python interpreter + void exec(const std::string& desc, const Geant4PythonCall& cmd) const; + + public: + /// Standard constructor + Geant4PythonDetectorConstruction(Geant4Context* c, const std::string& nam); + /// Default destructor + virtual ~Geant4PythonDetectorConstruction() {} + /// Set the Detector initialization command + void setConstructGeo(PyObject* callable, PyObject* args); + /// Set the field initialization command + void setConstructField(PyObject* callable, PyObject* args); + /// Set the sensitive detector initialization command + void setConstructSensitives(PyObject* callable, PyObject* args); + /// Geometry construction callback. Called at "Construct()" + virtual void constructGeo(Geant4DetectorConstructionContext* ctxt); + /// Electromagnetic field construction callback. Called at "ConstructSDandField()" + virtual void constructField(Geant4DetectorConstructionContext* ctxt); + /// Sensitive detector construction callback. Called at "ConstructSDandField()" + virtual void constructSensitives(Geant4DetectorConstructionContext* ctxt); + + }; + } // End namespace Simulation +} // End namespace DD4hep +#endif // DD4HEP_DDG4_GEANT4PYTHONDETECTORCONSTRUCTION_H diff --git a/DDG4/include/DDG4Python/Geant4PythonInitialization.h b/DDG4/include/DDG4Python/Geant4PythonInitialization.h new file mode 100644 index 0000000000000000000000000000000000000000..3b64d9fb5850ccf4c5d6db85bf414690a9eeb5d5 --- /dev/null +++ b/DDG4/include/DDG4Python/Geant4PythonInitialization.h @@ -0,0 +1,86 @@ +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ +#ifndef DD4HEP_DDG4_GEANT4PYTHONINITIALIZATION_H +#define DD4HEP_DDG4_GEANT4PYTHONINITIALIZATION_H + +// Framework include files +#include "DDG4/Geant4UserInitialization.h" +#include "DDG4Python/Geant4PythonCall.h" + +/// Namespace for the AIDA detector description toolkit +namespace DD4hep { + + /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit + namespace Simulation { + + /// Base class to initialize a multi-threaded or single threaded Geant4 application + /** + * Geant4PythonInitialization allows to configure python callbacks + * for the master and the worker thread setup using the calls: + * + * /// Set the Detector initialization command + * void setMasterSetup(PyObject* callable, PyObject* args); + * /// Set the field initialization command + * void setWorkerSetup(PyObject* callable, PyObject* args); + * + * or in python as a call sequence within the master thread: + * + * init_seq = kernel.userInitialization(True) + * init_action = UserInitialization(kernel,'Geant4PythonInitialization/PyG4Init') + * init_action.setWorkerSetup(worker_setup_call, < worker_args > ) + * init_action.setMasterSetup(master_setup_call, < master_args > ) + * init_seq.adopt(init_action) + * + * The callback argument list worker_args and master_args + * are python tuples containing all arguments expected by the callbacks + * worker_setup_call and master_setup_call respecyively. + * The class Geant4PythonInitialization is a subclass of + * Geant4UserInitialization and will call the provided functions + * according to the protocol explained earlier in this section. + * + * All python callbacks are supposed to return the integer '1' on success. + * Any other return code is assumed to be failure. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4PythonInitialization : public Geant4UserInitialization { + protected: + /// Master initialization command. Default: empty + Geant4PythonCall m_masterSetup; + /// Worker initialization command. Default: empty + Geant4PythonCall m_workerSetup; + + /// Execute command in the python interpreter + void exec(const std::string& desc, const Geant4PythonCall& cmd) const; + + public: + /// Standard constructor + Geant4PythonInitialization(Geant4Context* c, const std::string& nam); + /// Default destructor + virtual ~Geant4PythonInitialization() {} + + /// Set the Detector initialization command + void setMasterSetup(PyObject* callable, PyObject* args); + /// Set the field initialization command + void setWorkerSetup(PyObject* callable, PyObject* args); + /// Callback function to build setup for the MT worker thread + virtual void build() const; + /// Callback function to build setup for the MT master thread + virtual void buildMaster() const; + }; + } // End namespace Simulation +} // End namespace DD4hep +#endif // DD4HEP_DDG4_GEANT4PYTHONINITIALIZATION_H diff --git a/DDG4/lcio/Geant4Output2LCIO.cpp b/DDG4/lcio/Geant4Output2LCIO.cpp index abbdf18d9f79c042b866333e0f9e2549981e1e50..4ae43bf90bad763a6fc77276e3c008aa10ba34c9 100644 --- a/DDG4/lcio/Geant4Output2LCIO.cpp +++ b/DDG4/lcio/Geant4Output2LCIO.cpp @@ -18,6 +18,9 @@ // Framework include files #include "DD4hep/VolumeManager.h" #include "DDG4/Geant4OutputAction.h" +// Geant4 headers +#include "G4Threading.hh" +#include "G4AutoLock.hh" #include "DD4hep/LCDD.h" #include <G4Version.hh> @@ -125,6 +128,9 @@ namespace DD4hep { using namespace DD4hep::Simulation; using namespace DD4hep; using namespace std; +namespace { + G4Mutex action_mutex=G4MUTEX_INITIALIZER; +} #include "DDG4/Factories.h" DECLARE_GEANT4ACTION(Geant4Output2LCIO) @@ -139,6 +145,7 @@ Geant4Output2LCIO::Geant4Output2LCIO(Geant4Context* ctxt, const string& nam) /// Default destructor Geant4Output2LCIO::~Geant4Output2LCIO() { + G4AutoLock protection_lock(&action_mutex); if ( m_file ) { m_file->close(); deletePtr(m_file); @@ -149,6 +156,7 @@ Geant4Output2LCIO::~Geant4Output2LCIO() { // Callback to store the Geant4 run information void Geant4Output2LCIO::beginRun(const G4Run* ) { if ( 0 == m_file && !m_output.empty() ) { + G4AutoLock protection_lock(&action_mutex); m_file = lcio::LCFactory::getInstance()->createLCWriter(); m_file->open(m_output,lcio::LCIO::WRITE_NEW); } @@ -162,12 +170,17 @@ void Geant4Output2LCIO::endRun(const G4Run* run) { /// Commit data at end of filling procedure void Geant4Output2LCIO::commit( OutputContext<G4Event>& /* ctxt */) { lcio::LCEventImpl* e = context()->event().extension<lcio::LCEventImpl>(); - m_file->writeEvent(e); - // std::cout << " ########### Geant4Output2LCIO::commit() : writing LCIO event to file .... " << std::endl ; + if ( m_file ) { + G4AutoLock protection_lock(&action_mutex); + m_file->writeEvent(e); + return; + } + except("+++ Failed to write output file. [Stream is not open]"); } /// Callback to store the Geant4 run information void Geant4Output2LCIO::saveRun(const G4Run* run) { + G4AutoLock protection_lock(&action_mutex); // --- write an lcio::RunHeader --------- lcio::LCRunHeaderImpl* rh = new lcio::LCRunHeaderImpl; for (std::map< std::string, std::string >::iterator it = m_runHeader.begin(); it != m_runHeader.end(); ++it) { diff --git a/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp b/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4645b7ae0f6f0df691e49d4362608b8a59729f8d --- /dev/null +++ b/DDG4/plugins/Geant4DetectorGeometryConstruction.cpp @@ -0,0 +1,114 @@ +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-09 +// +//========================================================================== +// $Id$ + +// Framework include files +#include "DDG4/Geant4DetectorConstruction.h" + +/// Namespace for the AIDA detector description toolkit +namespace DD4hep { + + /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit + namespace Simulation { + + /// Class to create Geant4 detector geometry from TGeo representation in memory + /** + * On demand (ie. when calling "Construct") the DD4hep geometry is converted + * to Geant4 with all volumes, assemblies, shapes, materials etc. + * The actuak work is performed by the Geant4Converter class called by this method. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4DetectorGeometryConstruction : public Geant4DetectorConstruction { + /// Property: Dump geometry hierarchy + bool m_dumpHierarchy; + /// Property: G4 GDML dump file name (default: empty. If non empty, dump) + std::string m_dumpGDML; + + public: + /// Initializing constructor for DDG4 + Geant4DetectorGeometryConstruction(Geant4Context* ctxt, const std::string& nam); + /// Default destructor + virtual ~Geant4DetectorGeometryConstruction(); + /// Geometry construction callback. Called at "Construct()" + void constructGeo(Geant4DetectorConstructionContext* ctxt); + }; + } // End namespace Simulation +} // End namespace DD4hep + + +// Framework include files +#include "DD4hep/InstanceCount.h" +#include "DD4hep/Printout.h" +#include "DD4hep/LCDD.h" + +#include "DDG4/Geant4HierarchyDump.h" +#include "DDG4/Geant4Converter.h" +#include "DDG4/Geant4Kernel.h" +#include "DDG4/Factories.h" + +// Geant4 include files +#include "G4PVPlacement.hh" +#ifdef GEANT4_HAS_GDML +#include "G4GDMLParser.hh" +#endif + +using namespace std; +using namespace DD4hep; +using namespace DD4hep::Simulation; +DECLARE_GEANT4ACTION(Geant4DetectorGeometryConstruction) + +/// Initializing constructor for other clients +Geant4DetectorGeometryConstruction::Geant4DetectorGeometryConstruction(Geant4Context* ctxt, const string& nam) + : Geant4DetectorConstruction(ctxt,nam) +{ + declareProperty("DumpHierarchy", m_dumpHierarchy=false); + declareProperty("DumpGDML", m_dumpGDML=""); + InstanceCount::increment(this); +} + +/// Default destructor +Geant4DetectorGeometryConstruction::~Geant4DetectorGeometryConstruction() { + InstanceCount::decrement(this); +} + +/// Geometry construction callback. Called at "Construct()" +void Geant4DetectorGeometryConstruction::constructGeo(Geant4DetectorConstructionContext* ctxt) { + Geant4Mapping& g4map = Geant4Mapping::instance(); + Geometry::DetElement world = ctxt->lcdd.world(); + Geant4Converter conv(ctxt->lcdd, outputLevel()); + ctxt->geometry = conv.create(world).detach(); + g4map.attach(ctxt->geometry); + G4VPhysicalVolume* w = ctxt->geometry->world(); + ctxt->lcdd.apply("DD4hepVolumeManager", 0, 0); + // Create Geant4 volume manager + g4map.volumeManager(); + if ( m_dumpHierarchy ) { + Geant4HierarchyDump dmp(ctxt->lcdd); + dmp.dump("",w); + } +#ifdef GEANT4_HAS_GDML + const char* gdml_dmp = ::getenv("DUMP_GDML"); + if ( !m_dumpGDML.empty() || ) { + G4GDMLParser parser; + if ( !m_dumpGDML.empty() ) + parser.Write(m_dumpGDML.c_str(), w); + else if ( gdml_dmp ) + parser.Write(gdml_dmp, w); + } +#endif + ctxt->world = w; +} + diff --git a/DDG4/plugins/Geant4DetectorSensitivesConstruction.cpp b/DDG4/plugins/Geant4DetectorSensitivesConstruction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70620c6371c392c6d07af7c28a1df9d27f1cdc86 --- /dev/null +++ b/DDG4/plugins/Geant4DetectorSensitivesConstruction.cpp @@ -0,0 +1,123 @@ +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-09 +// +//========================================================================== +// $Id$ + +// Framework include files +#include "DDG4/Geant4DetectorConstruction.h" + +/// Namespace for the AIDA detector description toolkit +namespace DD4hep { + + /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit + namespace Simulation { + + /// Class to create Geant4 detector geometry from TGeo representation in memory + /** + * On demand the sensitive detectors are created and attached to all sensitive + * volumes. The relevant callback is executed when the call to + * ConstructSDandField() of the corresponding G4VUserDetectorConstruction + * instance is called. The call is thread-local! + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4DetectorSensitivesConstruction : public Geant4DetectorConstruction { + public: + /// Initializing constructor for DDG4 + Geant4DetectorSensitivesConstruction(Geant4Context* ctxt, const std::string& nam); + /// Default destructor + virtual ~Geant4DetectorSensitivesConstruction(); + /// Sensitives construction callback. Called at "ConstructSDandField()" + void constructSensitives(Geant4DetectorConstructionContext* ctxt); + }; + } // End namespace Simulation +} // End namespace DD4hep + + +// Framework include files +#include "DD4hep/InstanceCount.h" +#include "DD4hep/Printout.h" +#include "DD4hep/Plugins.h" +#include "DD4hep/LCDD.h" + +#include "DDG4/Geant4Mapping.h" +#include "DDG4/Factories.h" + +// ROOT include files +#include "TGeoManager.h" +// Geant4 include files +#include "G4SDManager.hh" +#include "G4PVPlacement.hh" +#include "G4VSensitiveDetector.hh" + +using namespace std; +using namespace DD4hep; +using namespace DD4hep::Simulation; + +DECLARE_GEANT4ACTION(Geant4DetectorSensitivesConstruction) + +/// Initializing constructor for other clients +Geant4DetectorSensitivesConstruction::Geant4DetectorSensitivesConstruction(Geant4Context* ctxt, const string& nam) + : Geant4DetectorConstruction(ctxt,nam) +{ + InstanceCount::increment(this); +} + +/// Default destructor +Geant4DetectorSensitivesConstruction::~Geant4DetectorSensitivesConstruction() { + InstanceCount::decrement(this); +} + +/// Sensitive detector construction callback. Called at "ConstructSDandField()" +void Geant4DetectorSensitivesConstruction::constructSensitives(Geant4DetectorConstructionContext* ctxt) { + typedef Geometry::GeoHandlerTypes::SensitiveVolumes _SV; + typedef Geometry::GeoHandlerTypes::ConstVolumeSet VolSet; + Geant4GeometryInfo* p = Geant4Mapping::instance().ptr(); + G4VSensitiveDetector* g4sd = 0; + _SV& vols = p->sensitives; + + for(_SV::const_iterator iv=vols.begin(); iv != vols.end(); ++iv) { + Geometry::SensitiveDetector sd = (*iv).first; + string typ = sd.type(), nam = sd.name(); + g4sd = PluginService::Create<G4VSensitiveDetector*>(typ, nam, &ctxt->lcdd); + if (!g4sd) { + string tmp = typ; + tmp[0] = ::toupper(tmp[0]); + typ = "Geant4" + tmp; + g4sd = PluginService::Create<G4VSensitiveDetector*>(typ, nam, &ctxt->lcdd); + if ( !g4sd ) { + PluginDebug dbg; + g4sd = PluginService::Create<G4VSensitiveDetector*>(typ, nam, &ctxt->lcdd); + if ( !g4sd ) { + throw runtime_error("ConstructSDandField: FATAL Failed to " + "create Geant4 sensitive detector " + nam + + " of type " + typ + "."); + } + } + } + g4sd->Activate(true); + G4SDManager::GetSDMpointer()->AddNewDetector(g4sd); + const VolSet& sens_vols = (*iv).second; + for(VolSet::const_iterator i=sens_vols.begin(); i!= sens_vols.end(); ++i) { + const TGeoVolume* vol = *i; + G4LogicalVolume* g4v = p->g4Volumes[vol]; + if ( !g4v ) { + throw runtime_error("ConstructSDandField: Failed to access G4LogicalVolume for SD "+ + nam + " of type " + typ + "."); + } + ctxt->setSensitiveDetector(g4v,g4sd); + } + } + print("Geant4Converter", "++ Handled %ld sensitive detectors.",vols.size()); +} diff --git a/DDG4/plugins/Geant4Factories.cpp b/DDG4/plugins/Geant4Factories.cpp index 03bb7e6054de1eef32acc118e1c35ee9649ad88c..bec66e5d6a3a7709891cd04f674e0d53c5fe2404 100644 --- a/DDG4/plugins/Geant4Factories.cpp +++ b/DDG4/plugins/Geant4Factories.cpp @@ -23,33 +23,46 @@ DECLARE_GEANT4ACTION(Geant4Random) DECLARE_GEANT4ACTION(Geant4PhaseAction) #include "DDG4/Geant4RunAction.h" +DECLARE_GEANT4ACTION(Geant4SharedRunAction) DECLARE_GEANT4ACTION(Geant4RunActionSequence) #include "DDG4/Geant4EventAction.h" +DECLARE_GEANT4ACTION(Geant4SharedEventAction) DECLARE_GEANT4ACTION(Geant4EventActionSequence) #include "DDG4/Geant4SteppingAction.h" +DECLARE_GEANT4ACTION(Geant4SharedSteppingAction) DECLARE_GEANT4ACTION(Geant4SteppingActionSequence) #include "DDG4/Geant4TrackingAction.h" +DECLARE_GEANT4ACTION(Geant4SharedTrackingAction) DECLARE_GEANT4ACTION(Geant4TrackingActionSequence) #include "DDG4/Geant4StackingAction.h" +DECLARE_GEANT4ACTION(Geant4SharedStackingAction) DECLARE_GEANT4ACTION(Geant4StackingActionSequence) #include "DDG4/Geant4GeneratorAction.h" +DECLARE_GEANT4ACTION(Geant4SharedGeneratorAction) DECLARE_GEANT4ACTION(Geant4GeneratorActionSequence) #include "DDG4/Geant4PhysicsList.h" DECLARE_GEANT4ACTION(Geant4PhysicsList) DECLARE_GEANT4ACTION(Geant4PhysicsListActionSequence) +#include "DDG4/Geant4DetectorConstruction.h" +DECLARE_GEANT4ACTION(Geant4DetectorConstruction) +DECLARE_GEANT4ACTION(Geant4DetectorConstructionSequence) + #include "DDG4/Geant4SensDetAction.h" DECLARE_GEANT4ACTION(Geant4SensDetActionSequence) #include "DDG4/Geant4UIManager.h" DECLARE_GEANT4ACTION(Geant4UIManager) +#include "DDG4/Geant4UserInitialization.h" +DECLARE_GEANT4ACTION(Geant4UserInitializationSequence) + #include "DDG4/Geant4MonteCarloTruth.h" DECLARE_GEANT4ACTION(Geant4DummyTruthHandler) diff --git a/DDG4/plugins/Geant4FieldTrackingSetup.cpp b/DDG4/plugins/Geant4FieldTrackingSetup.cpp index 56fa11ea9e6cfef346eb25b4959b85ca61f123ff..937c1e03380681efa56149d08382d31a2b1da51a 100644 --- a/DDG4/plugins/Geant4FieldTrackingSetup.cpp +++ b/DDG4/plugins/Geant4FieldTrackingSetup.cpp @@ -18,7 +18,7 @@ // Framework include files #include "DD4hep/LCDD.h" #include "DDG4/Geant4ActionPhase.h" - +#include "DDG4/Geant4DetectorConstruction.h" /// Namespace for the AIDA detector description toolkit namespace DD4hep { @@ -76,7 +76,10 @@ namespace DD4hep { * @author M.Frank * @version 1.0 */ - class Geant4FieldTrackingSetupAction : public Geant4PhaseAction, public Geant4FieldTrackingSetup { + class Geant4FieldTrackingSetupAction : + public Geant4PhaseAction, + public Geant4FieldTrackingSetup + { protected: public: /// Standard constructor @@ -89,6 +92,32 @@ namespace DD4hep { void operator()(); }; + + /// Detector construction action to perform the setup of the Geant4 tracking in magnetic fields + /** Geant4FieldTrackingSetupAction. + * + * The phase action configures the Geant4FieldTrackingSetup base class using properties + * and then configures the Geant4 tracking in magnetic fields. + * + * @author M.Frank + * @version 1.0 + */ + class Geant4FieldTrackingConstruction : + public Geant4DetectorConstruction, + public Geant4FieldTrackingSetup + { + protected: + public: + /// Standard constructor + Geant4FieldTrackingConstruction(Geant4Context* context, const std::string& nam); + + /// Default destructor + virtual ~Geant4FieldTrackingConstruction() {} + + /// Phase action callback + void operator()(); + + }; } // End namespace Simulation } // End namespace DD4hep #endif // DD4HEP_DDG4_GEANT4FIELDTRACKINGSETUP_H @@ -234,5 +263,30 @@ void Geant4FieldTrackingSetupAction::operator()() { delta_chord,delta_one_step,delta_intersection); } + +/// Standard constructor +Geant4FieldTrackingConstruction::Geant4FieldTrackingConstruction(Geant4Context* ctxt, const std::string& nam) + : Geant4DetectorConstruction(ctxt,nam), Geant4FieldTrackingSetup() +{ + declareProperty("equation", eq_typ); + declareProperty("stepper", stepper_typ); + declareProperty("min_chord_step", min_chord_step = 1.0e-2); + declareProperty("delta_chord", delta_chord = -1.0); + declareProperty("delta_one_step", delta_one_step = -1.0); + declareProperty("delta_intersection", delta_intersection = -1.0); + declareProperty("eps_min", eps_min = -1.0); + declareProperty("eps_max", eps_max = -1.0); +} + +/// Post-track action callback +void Geant4FieldTrackingConstruction::operator()() { + execute(context()->lcdd()); + print("Geant4 magnetic field tracking configured. G4MagIntegratorStepper:%s G4Mag_EqRhs:%s " + "Epsilon:[min:%f mm max:%f mm] Delta:[chord:%f 1-step:%f intersect:%f]", + stepper_typ.c_str(),eq_typ.c_str(),eps_min, eps_max, + delta_chord,delta_one_step,delta_intersection); +} + DECLARE_GEANT4_SETUP(Geant4FieldSetup,setup_fields) DECLARE_GEANT4ACTION(Geant4FieldTrackingSetupAction) +DECLARE_GEANT4ACTION(Geant4FieldTrackingConstruction) diff --git a/DDG4/plugins/Geant4MaterialScanner.cpp b/DDG4/plugins/Geant4MaterialScanner.cpp index 700a6e0f3f27bedca828298419d4aba5ad2147bb..dd7a03d6cd81a40ec9e4a6e74f11cb13c7113461 100644 --- a/DDG4/plugins/Geant4MaterialScanner.cpp +++ b/DDG4/plugins/Geant4MaterialScanner.cpp @@ -97,9 +97,8 @@ namespace DD4hep { #include "G4Material.hh" using namespace std; -using namespace CLHEP; - using namespace DD4hep::Simulation; + #include "DDG4/Factories.h" DECLARE_GEANT4ACTION(Geant4MaterialScanner) @@ -173,6 +172,7 @@ void Geant4MaterialScanner::begin(const G4Track* track) { /// End-of-tracking callback void Geant4MaterialScanner::end(const G4Track* track) { + using namespace CLHEP; if ( !m_steps.empty() ) { const char* line = " +--------------------------------------------------------------------------------------------------------------------------------------------------\n"; const char* fmt1 = " | %5d %-20s %3.0f %8.3f %8.4f %11.4f %11.4f %10.3f %8.2f %11.6f %11.6f (%7.2f,%7.2f,%7.2f)\n"; @@ -189,28 +189,28 @@ void Geant4MaterialScanner::end(const G4Track* track) { int count = 1; for(Steps::const_iterator i=m_steps.begin(); i!=m_steps.end(); ++i, ++count) { const G4LogicalVolume* logVol = (*i)->volume; - G4Material* m = logVol->GetMaterial(); + G4Material* material = logVol->GetMaterial(); const Position& prePos = (*i)->pre; const Position& postPos = (*i)->post; Position direction = postPos - prePos; double length = direction.R()/cm; - double intLen = m->GetNuclearInterLength()/cm; - double radLen = m->GetRadlen()/cm; - double density = m->GetDensity()/(gram/cm3); + double intLen = material->GetNuclearInterLength()/cm; + double radLen = material->GetRadlen()/cm; + double density = material->GetDensity()/(gram/cm3); double nLambda = length / intLen; double nx0 = length / radLen; double Aeff = 0.0; double Zeff = 0.0; const char* fmt = radLen >= 1e5 ? fmt2 : fmt1; - const double* fractions = m->GetFractionVector(); - for(size_t j=0; j<m->GetNumberOfElements(); ++j) { - Zeff += fractions[j]*(m->GetElement(j)->GetZ()); - Aeff += fractions[j]*(m->GetElement(j)->GetA())/gram; + const double* fractions = material->GetFractionVector(); + for(size_t j=0; j<material->GetNumberOfElements(); ++j) { + Zeff += fractions[j]*(material->GetElement(j)->GetZ()); + Aeff += fractions[j]*(material->GetElement(j)->GetA())/gram; } m_sumX0 += nx0; m_sumLambda += nLambda; m_sumPath += length; - ::printf(fmt,count,m->GetName().c_str(), + ::printf(fmt,count,material->GetName().c_str(), Zeff, Aeff, density, radLen, intLen, length, m_sumPath,m_sumX0,m_sumLambda, postPos.X()/cm,postPos.Y()/cm,postPos.Z()/cm); diff --git a/DDG4/plugins/Geant4SensDet.cpp b/DDG4/plugins/Geant4SensDet.cpp index b0d72aebb2e48ae1f2c9fd78ef9058ee448db678..3bc22c80a6966412b3a25108b78edf404e7b8425 100644 --- a/DDG4/plugins/Geant4SensDet.cpp +++ b/DDG4/plugins/Geant4SensDet.cpp @@ -33,8 +33,6 @@ namespace DD4hep { /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit namespace Simulation { - Geant4Context* ddg4_globalContext(); - /// Private helper to support sequence reference counting /** * \author M.Frank @@ -82,12 +80,14 @@ namespace DD4hep { : G4VSensitiveDetector(nam), G4VSDFilter(nam), Geant4Action(0,nam), Geant4ActionSD(nam), Base() { - Geant4Kernel& kernel = Geant4Kernel::access(lcdd); - m_sensitive = lcdd.sensitiveDetector(nam); - m_context = Geant4Context(&kernel); + Geant4Kernel& master = Geant4Kernel::access(lcdd); + Geant4Kernel& kernel = master.worker(::pthread_self()); + m_sensitive = lcdd.sensitiveDetector(nam); + m_context = kernel.workerContext(); m_outputLevel = kernel.getOutputLevel(nam); _aquire(kernel.sensitiveAction(nam)); m_sequence->defineCollections(this); + m_sequence->updateContext(m_context); this->G4VSensitiveDetector::SetFilter(this); } @@ -121,25 +121,11 @@ namespace DD4hep { virtual G4bool Accept(const G4Step* step) const { return m_sequence->accept(step); } /// Method invoked at the begining of each event. - virtual void Initialize(G4HCofThisEvent* hce) { - m_context.setRun(&ddg4_globalContext()->run()); - m_context.setEvent(&ddg4_globalContext()->event()); - (Geant4Action::ContextUpdate(&m_context))(m_sequence); - m_sequence->begin(hce); -#if 0 - const G4Event& evt = context()->event(); - error(name(), "%s> calling Initialize(event_id=%d Context: run=%p (%d) evt=%p (%d))", - GetName().c_str(), evt.GetEventID(), - &context()->run(), context()->run().run().GetRunID(), - &context()->event(), context()->event().event().GetEventID()); -#endif - } + virtual void Initialize(G4HCofThisEvent* hce) + { m_sequence->begin(hce); } /// Method invoked at the end of each event. - virtual void EndOfEvent(G4HCofThisEvent* hce) { - m_sequence->end(hce); - m_context.setEvent(0); - (Geant4Action::ContextUpdate(&m_context))(m_sequence); - } + virtual void EndOfEvent(G4HCofThisEvent* hce) + { m_sequence->end(hce); } /// Method for generating hit(s) using the information of G4Step object. virtual G4bool ProcessHits(G4Step* step,G4TouchableHistory* hist) { return m_sequence->process(step,hist); } diff --git a/DDG4/plugins/Geant4TrackerWeightedSD.cpp b/DDG4/plugins/Geant4TrackerWeightedSD.cpp index b67f340b81621153558c6049bc679d7889280b65..ee51e48aa71c54a024847a8a1bc002472a1c39e0 100644 --- a/DDG4/plugins/Geant4TrackerWeightedSD.cpp +++ b/DDG4/plugins/Geant4TrackerWeightedSD.cpp @@ -337,7 +337,7 @@ namespace DD4hep { } /// Post-event action callback - void endEvent(const G4Event*) { + void endEvent() { // We need to add the possibly last added hit to the collection here. // otherwise the last hit would be assigned to the next event and the // MC truth would be screwed. @@ -349,11 +349,8 @@ namespace DD4hep { } } /// Pre event action callback - void startEvent(const G4Event* event) { + void startEvent() { thisSD = dynamic_cast<G4VSensitiveDetector*>(&sensitive->detector()); - if ( event ) { - sensitive->print("++++++++++++++++++++++++++ START EVENT %d",event->GetEventID()); - } } }; @@ -361,12 +358,20 @@ namespace DD4hep { template <> void Geant4SensitiveAction<TrackerWeighted>::initialize() { declareProperty("HitPostionCombination", m_userData.hit_position_type); declareProperty("CollectSingleDeposits", m_userData.single_deposit_mode); - eventAction().callAtBegin(&m_userData,&TrackerWeighted::startEvent); - eventAction().callAtEnd(&m_userData,&TrackerWeighted::endEvent); m_userData.e_cut = m_sensitive.energyCutoff(); m_userData.sensitive = this; } + /// G4VSensitiveDetector interface: Method invoked at the begining of each event. + template <> void Geant4SensitiveAction<TrackerWeighted>::begin(G4HCofThisEvent* hce) { + m_userData.startEvent(); + } + + /// G4VSensitiveDetector interface: Method invoked at the end of each event. + template <> void Geant4SensitiveAction<TrackerWeighted>::end(G4HCofThisEvent* hce) { + m_userData.endEvent(); + } + /// Define collections created by this sensitivie action object template <> void Geant4SensitiveAction<TrackerWeighted>::defineCollections() { m_collectionID = defineCollection<Geant4Tracker::Hit>(m_sensitive.readout().name()); diff --git a/DDG4/plugins/Geant4UserActionInitialization.cpp b/DDG4/plugins/Geant4UserActionInitialization.cpp new file mode 100644 index 0000000000000000000000000000000000000000..41dfec1cce24f67dadfc55e8ce719b3c1d9799c1 --- /dev/null +++ b/DDG4/plugins/Geant4UserActionInitialization.cpp @@ -0,0 +1,90 @@ +#if 0 +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ +#ifndef DD4HEP_DDG4_GEANT4USERACTIONINITIALIZATION_H +#define DD4HEP_DDG4_GEANT4USERACTIONINITIALIZATION_H + +// Framework include files +#include "DDG4/Geant4UserInitialization.h" + +/// Namespace for the AIDA detector description toolkit +namespace DD4hep { + + /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit + namespace Simulation { + + /// Base class to initialize a multi-threaded or single threaded Geant4 application + /** + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4UserActionInitialization : public Geant4UserInitialization { + public: + /// Standard constructor + Geant4UserActionInitialization(Geant4Context* c, const std::string& nam); + /// Default destructor + virtual ~Geant4UserActionInitialization() {} + + /// Callback function to build setup for the MT worker thread + virtual void build(); + /// Callback function to build setup for the MT master thread + virtual void buildMaster(); + }; + } // End namespace Simulation +} // End namespace DD4hep +#endif // DD4HEP_DDG4_GEANT4USERACTIONINITIALIZATION_H + + +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ + +// Framework include files +#include "DDG4/Factories.h" +//#include "DDG4/Geant4UserActionInitialization.h" +#include "DDG4/Geant4Context.h" + +// C/C++ include files + +using namespace std; +using namespace DD4hep::Simulation; + +//DECLARE_GEANT4ACTION(Geant4UserActionInitialization) + +/// Standard constructor, initializes variables +Geant4UserActionInitialization::Geant4UserActionInitialization(Geant4Context* ctxt, const string& nam) + : Geant4UserInitialization(ctxt,nam) +{ +} + +/// Callback function to build setup for the MT worker thread +void Geant4UserActionInitialization::build() { + +} + +/// Callback function to build setup for the MT master thread +void Geant4UserActionInitialization::buildMaster() { +} +#endif diff --git a/DDG4/pyddg4.cpp b/DDG4/pyddg4.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91cae04f7ffa7d1bfc9cf07a961864da165cb315 --- /dev/null +++ b/DDG4/pyddg4.cpp @@ -0,0 +1,79 @@ +// $Id$ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// Author : M.Frank +// +//========================================================================== +#include "TSystem.h" +#include "TInterpreter.h" +#include "DDG4Python/DDPython.h" +#include "Python.h" +#include <string> +#include <vector> +using namespace std; +using namespace DD4hep; + +static int load_libs(const vector<char*>& libs) { + for(size_t i=0; i<libs.size(); ++i) { + int ret = gSystem->Load(libs[i]); + if ( 0 != ret ) { + ::printf("+++ Failed to load library: %s [ignored]\n",libs[i]); + return ret; + } + else { + ::printf("+++ Successfully loaded library: %s\n",libs[i]); + } + } + return 0; +} + +int main(int argc, char** argv) { + bool have_prompt = false; + bool do_execute = false; + vector<char*> args; + vector<char*> libs; + int first_arg = 1; + int ret; + + if ( argc>first_arg && strncmp(argv[first_arg],"-p",2)==0 ) { + have_prompt = true; + args.push_back(argv[0]); + ++first_arg; + } + else if ( argc>first_arg && strncmp(argv[first_arg],"-e",2)==0 ) { + do_execute = true; + ++first_arg; + } + for(int i=first_arg; i<argc; ++i) { + if ( 0 == ::strcmp(argv[i],"-L") ) + libs.push_back(argv[++i]); + else + args.push_back(argv[i]); + } + if ( !have_prompt && args.size()>0 ) { + libs.push_back((char*)"libDDG4Python"); + if ( 0 == (ret=load_libs(libs)) ) { + DDPython::instance().setArgs(args.size(), &args[0]); + DDPython::instance().setMainThread(); + DDPython::instance().runFile(args[0]); + if ( do_execute ) + return gInterpreter->ProcessLine("PyDDG4::execute()"); + else + return 0; + } + return ret; + } + if ( 0 == (ret=load_libs(libs)) ) { + ::printf("+++ Calling now Py_Main...\n"); + ret = ::Py_Main(args.size(), &args[0]); + //::printf("+++ Return code Py_Main=%d\n",ret); + } + return ret; +} diff --git a/DDG4/python/DD4hep.py b/DDG4/python/DD4hep.py index aaf6c3848d899c4c989df1dbb7ba889746c0e6de..16d4a1a780db29f51a58cce0070066c18163558f 100644 --- a/DDG4/python/DD4hep.py +++ b/DDG4/python/DD4hep.py @@ -26,6 +26,7 @@ def compileAClick(dictionary,g4=True): gSystem.AddIncludePath(inc) gSystem.AddLinkedLibs(lib) #####print "Includes: ",gSystem.GetIncludePath(),"\n","Linked libs:",gSystem.GetLinkedLibs() + print 'Loading AClick ',dictionary package = imp.find_module('DDG4') dic = os.path.dirname(package[1])+os.sep+dictionary ###print dic @@ -95,6 +96,7 @@ import_namespace_item('Core','run_interpreter') def import_geometry(): import_namespace_item('Core','setPrintLevel') + import_namespace_item('Core','setPrintFormat') import_namespace_item('Core','printLevel') import_namespace_item('Geo','LCDD') import_namespace_item('Core','evaluator') diff --git a/DDG4/python/DDG4.py b/DDG4/python/DDG4.py index 8dbc0c8159efd7565b9d74cc1df49cc2ab7716e1..61c4f4567cecd9916b65301c012dfcb28053da33 100644 --- a/DDG4/python/DDG4.py +++ b/DDG4/python/DDG4.py @@ -130,38 +130,59 @@ def _setKernelProperty(self, name, value): #--------------------------------------------------------------------------- def _kernel_phase(self,name): return self.addSimplePhase(name,False) #--------------------------------------------------------------------------- +def _kernel_worker(self): return Kernel(self.get().createWorker()) +#--------------------------------------------------------------------------- Kernel.phase = _kernel_phase Kernel.registerGlobalAction = _registerGlobalAction Kernel.registerGlobalFilter = _registerGlobalFilter +Kernel.createWorker = _kernel_worker Kernel.__getattr__ = _getKernelProperty Kernel.__setattr__ = _setKernelProperty #--------------------------------------------------------------------------- -ActionHandle = Sim.ActionHandle +ActionHandle = Sim.ActionHandle +#--------------------------------------------------------------------------- +def SensitiveAction(kernel,nam,det,shared=False): + return Interface.createSensitive(kernel,nam,det,shared) +#--------------------------------------------------------------------------- +def Action(kernel,nam,shared=False): + return Interface.createAction(kernel,nam,shared) #--------------------------------------------------------------------------- -def SensitiveAction(kernel,nam,det): return Interface.createSensitive(kernel,nam,det) +def Filter(kernel,nam,shared=False): + return Interface.createFilter(kernel,nam,shared) #--------------------------------------------------------------------------- -def Action(kernel,nam): return Interface.createAction(kernel,nam) +def PhaseAction(kernel,nam,shared=False): + return Interface.createPhaseAction(kernel,nam,shared) #--------------------------------------------------------------------------- -def Filter(kernel,nam): return Interface.createFilter(kernel,nam) +def RunAction(kernel,nam,shared=False): + return Interface.createRunAction(kernel,nam,shared) #--------------------------------------------------------------------------- -def PhaseAction(kernel,nam): return Interface.createPhaseAction(kernel,nam) +def EventAction(kernel,nam,shared=False): + return Interface.createEventAction(kernel,nam,shared) #--------------------------------------------------------------------------- -def RunAction(kernel,nam): return Interface.createRunAction(kernel,nam) +def GeneratorAction(kernel,nam,shared=False): + return Interface.createGeneratorAction(kernel,nam,shared) #--------------------------------------------------------------------------- -def EventAction(kernel,nam): return Interface.createEventAction(kernel,nam) +def TrackingAction(kernel,nam,shared=False): + return Interface.createTrackingAction(kernel,nam,shared) #--------------------------------------------------------------------------- -def GeneratorAction(kernel,nam): return Interface.createGeneratorAction(kernel,nam) +def SteppingAction(kernel,nam,shared=False): + return Interface.createSteppingAction(kernel,nam,shared) #--------------------------------------------------------------------------- -def TrackingAction(kernel,nam): return Interface.createTrackingAction(kernel,nam) +def StackingAction(kernel,nam,shared=False): + return Interface.createStackingAction(kernel,nam,shared) #--------------------------------------------------------------------------- -def SteppingAction(kernel,nam): return Interface.createSteppingAction(kernel,nam) +def DetectorConstruction(kernel,nam): + return Interface.createDetectorConstruction(kernel,nam) #--------------------------------------------------------------------------- -def StackingAction(kernel,nam): return Interface.createStackingAction(kernel,nam) +def PhysicsList(kernel,nam): + return Interface.createPhysicsList(kernel,nam) #--------------------------------------------------------------------------- -def PhysicsList(kernel,nam): return Interface.createPhysicsList(kernel,nam) +def UserInitialization(kernel, nam): + return Interface.createUserInitialization(kernel,nam) #--------------------------------------------------------------------------- -def SensitiveSequence(kernel, nam): return Interface.createSensDetSequence(kernel,nam) +def SensitiveSequence(kernel, nam): + return Interface.createSensDetSequence(kernel,nam) #--------------------------------------------------------------------------- def _setup(obj): def _adopt(self,action): self.__adopt(action.get()) @@ -188,12 +209,18 @@ _setup('Geant4SteppingActionSequence') _setup('Geant4StackingActionSequence') _setup('Geant4PhysicsListActionSequence') _setup('Geant4SensDetActionSequence') +_setup('Geant4DetectorConstructionSequence') +_setup('Geant4UserInitializationSequence') _setup('Geant4Sensitive') _setup('Geant4ParticleHandler') _import_class('Sim','Geant4Filter') _import_class('Sim','Geant4RunAction') +_import_class('Sim','Geant4TrackingAction') +_import_class('Sim','Geant4StackingAction') _import_class('Sim','Geant4PhaseAction') _import_class('Sim','Geant4UserParticleHandler') +_import_class('Sim','Geant4UserInitialization') +_import_class('Sim','Geant4DetectorConstruction') #--------------------------------------------------------------------------- def _get(self, name): @@ -238,7 +265,9 @@ _props('PhysicsListHandle') _props('TrackingActionHandle') _props('SteppingActionHandle') _props('StackingActionHandle') +_props('DetectorConstructionHandle') _props('SensitiveHandle') +_props('UserInitializationHandle') _props('Geant4ParticleHandler') _props('Geant4UserParticleHandler') @@ -248,8 +277,10 @@ _props('EventActionSequenceHandle') _props('TrackingActionSequenceHandle') _props('SteppingActionSequenceHandle') _props('StackingActionSequenceHandle') +_props('DetectorConstructionSequenceHandle') _props('PhysicsListActionSequenceHandle') _props('SensDetActionSequenceHandle') +_props('UserInitializationSequenceHandle') _props('Geant4PhysicsListActionSequence') @@ -266,18 +297,26 @@ _props('Geant4PhysicsListActionSequence') \version 1.0 """ -class Simple: - def __init__(self, kernel=None,calo='Geant4CalorimeterAction',tracker='Geant4SimpleTrackerAction'): +class Geant4: + def __init__(self, kernel=None, + calo='Geant4CalorimeterAction', + tracker='Geant4SimpleTrackerAction'): kernel.UI = "UI" kernel.printProperties() - self.kernel = kernel + self._kernel = kernel if kernel is None: - self.kernel = Kernel() - self.lcdd = self.kernel.lcdd() + self._kernel = Kernel() + self.lcdd = self._kernel.lcdd() self.sensitive_types = {} self.sensitive_types['tracker'] = tracker self.sensitive_types['calorimeter'] = calo + + def kernel(self): + return self._kernel.worker() + def master(self): + return self._kernel + """ Configure the Geant4 command executive @@ -285,7 +324,7 @@ class Simple: """ def setupUI(self,typ='csh',vis=False,ui=True,macro=None): # Configure UI - ui_action = Action(self.kernel,"Geant4UIManager/UI") + ui_action = Action(self.master(),"Geant4UIManager/UI") if vis: ui_action.HaveVIS = True else: ui_action.HaveVIS = False if ui: ui_action.HaveUI = True @@ -293,7 +332,7 @@ class Simple: ui_action.SessionType = typ if macro: ui_action.SetupUI = macro - self.kernel.registerGlobalAction(ui_action) + self.master().registerGlobalAction(ui_action) return ui_action """ @@ -304,14 +343,66 @@ class Simple: def setupCshUI(self,typ='csh',vis=False,ui=True,macro=None): return self.setupUI(typ='csh',vis=vis,ui=ui,macro=macro) + """ + Configure Geant4 user initialization for optionasl multi-threading mode + + \author M.Frank + """ + def addUserInitialization(self, worker, worker_args=None, master=None, master_args=None): + import sys + init_seq = self.master().userInitialization(True) + init_action = UserInitialization(self.master(),'Geant4PythonInitialization/PyG4Init') + # + if worker: + init_action.setWorkerSetup(worker, worker_args) + else: + raise exceptions.RuntimeError('Invalid argument for Geant4 worker initialization') + # + if master: + init_action.setMasterSetup(master,master_args) + # + init_seq.adopt(init_action) + return init_seq,init_action + + """ + Configure Geant4 user initialization for optionasl multi-threading mode + + \author M.Frank + """ + def addDetectorConstruction(self, name_type, + field=None, field_args=None, + geometry=None, geometry_args=None, + sensitives=None, sensitives_args=None, + allow_threads=False): + init_seq = self.master().detectorConstruction(True) + init_action = DetectorConstruction(self.master(),name_type) + # + if geometry: + init_action.setConstructGeo(geometry,geometry_args) + # + if field: + init_action.setConstructField(field,field_args) + # + if sensitives: + init_action.setConstructSensitives(sensitives,sensitives_args) + # + init_seq.adopt(init_action) + if allow_threads: + last_action = DetectorConstruction(self.master(),"Geant4PythonDetectorConstructionLast/LastDetectorAction") + init_seq.adopt(last_action) + + return init_seq,init_action + """ Add a new phase action to an arbitrary step. \author M.Frank """ - def addPhaseAction(self,phase_name,factory_specification,ui=True): - action = PhaseAction(self.kernel,factory_specification) - self.kernel.phase('configure').add(action) + def addPhaseAction(self,phase_name,factory_specification,ui=True,instance=None): + if instance is None: + instance = self.kernel() + action = PhaseAction(instance,factory_specification) + instance.phase(phase_name).add(action) if ui: action.enableUI() return action @@ -324,7 +415,7 @@ class Simple: \author M.Frank """ def addConfig(self, factory_specification): - return self.addPhaseAction('configure',factory_specification) + return self.addPhaseAction('configure',factory_specification,instance=self.master()) """ Add a new phase action to the 'initialize' step. @@ -365,10 +456,10 @@ class Simple: \author M.Frank """ def execute(self): - self.kernel.configure() - self.kernel.initialize() - self.kernel.run() - self.kernel.terminate() + self.kernel().configure() + self.kernel().initialize() + self.kernel().run() + self.kernel().terminate() return self def printDetectors(self): @@ -384,8 +475,8 @@ class Simple: print '+++ %-32s type:%-12s --> Sensitive type: %s'%(o.name(), typ, sdtyp,) def setupDetector(self,name,sensitive_type): - seq = SensitiveSequence(self.kernel,'Geant4SensDetActionSequence/'+name) - act = SensitiveAction(self.kernel,sensitive_type+'/'+name+'Handler',name) + seq = SensitiveSequence(self.kernel(),'Geant4SensDetActionSequence/'+name) + act = SensitiveAction(self.kernel(),sensitive_type+'/'+name+'Handler',name) seq.enableUI() act.enableUI() seq.add(act) @@ -404,7 +495,7 @@ class Simple: return self.setupDetector(name,type) def setupPhysics(self,name): - phys = self.kernel.physicsList() + phys = self.master().physicsList() phys.extends = name phys.decays = True phys.enableUI() @@ -412,14 +503,14 @@ class Simple: return phys def setupGun(self, name, particle, energy, isotrop=True, multiplicity=1, position=(0.0,0.0,0.0)): - gun = GeneratorAction(self.kernel,"Geant4ParticleGun/"+name) + gun = GeneratorAction(self.kernel(),"Geant4ParticleGun/"+name,True) gun.energy = energy gun.particle = particle gun.multiplicity = multiplicity gun.position = position gun.isotrop = isotrop gun.enableUI() - self.kernel.generatorAction().add(gun) + self.kernel().generatorAction().add(gun) return gun """ @@ -428,12 +519,14 @@ class Simple: \author M.Frank """ def setupROOTOutput(self,name,output,mc_truth=True): - evt_root = EventAction(self.kernel,'Geant4Output2ROOT/'+name) + evt_root = EventAction(self.kernel(),'Geant4Output2ROOT/'+name,True) evt_root.HandleMCTruth = mc_truth evt_root.Control = True - evt_root.Output = output + '' if output.endswith('.root') else '.root' + if not output.endswith('.root'): + output = output + '.root' + evt_root.Output = output evt_root.enableUI() - self.kernel.eventAction().add(evt_root) + self.kernel().eventAction().add(evt_root) return evt_root """ @@ -442,11 +535,11 @@ class Simple: \author M.Frank """ def setupLCIOOutput(self,name,output): - evt_lcio = EventAction(self.kernel,'Geant4Output2LCIO/'+name) + evt_lcio = EventAction(self.kernel(),'Geant4Output2LCIO/'+name,True) evt_lcio.Control = True evt_lcio.Output = output evt_lcio.enableUI() - self.kernel.eventAction().add(evt_lcio) + self.kernel().eventAction().add(evt_lcio) return evt_lcio """ @@ -462,9 +555,9 @@ class Simple: \author M.Frank """ def buildInputStage(self, generator_input_modules, output_level=None, have_mctruth=True): - ga = self.kernel.generatorAction() + ga = self.kernel().generatorAction() # Register Generation initialization action - gen = GeneratorAction(self.kernel,"Geant4GeneratorActionInit/GenerationInit") + gen = GeneratorAction(self.kernel(),"Geant4GeneratorActionInit/GenerationInit") if output_level is not None: gen.OutputLevel = output_level ga.adopt(gen) @@ -478,7 +571,7 @@ class Simple: ga.adopt(gen) # Merge all existing interaction records - gen = GeneratorAction(self.kernel,"Geant4InteractionMerger/InteractionMerger") + gen = GeneratorAction(self.kernel(),"Geant4InteractionMerger/InteractionMerger") gen.enableUI() if output_level is not None: gen.OutputLevel = output_level @@ -486,7 +579,7 @@ class Simple: # Finally generate Geant4 primaries if have_mctruth: - gen = GeneratorAction(self.kernel,"Geant4PrimaryHandler/PrimaryHandler") + gen = GeneratorAction(self.kernel(),"Geant4PrimaryHandler/PrimaryHandler") gen.enableUI() if output_level is not None: gen.OutputLevel = output_level @@ -494,4 +587,16 @@ class Simple: # Puuuhh! All done. return self -Geant4 = Simple + """ + Execute the main Geant4 action + \author M.Frank + """ + def run(self): + #self.master().configure() + #self.master().initialize() + #self.master().run() + #self.master().terminate() + from ROOT import PyDDG4 + PyDDG4.run(self.master().get()) + +Simple = Geant4 diff --git a/DDG4/python/DDG4Dict.C b/DDG4/python/DDG4Dict.C index ea0602cfd31940a22c7527540dd2f6162bdaa155..476d3d1692df29cb0720bffd422de9400a54897e 100644 --- a/DDG4/python/DDG4Dict.C +++ b/DDG4/python/DDG4Dict.C @@ -56,8 +56,10 @@ namespace DD4hep { ACTIONHANDLE(TrackingAction); ACTIONHANDLE(SteppingAction); ACTIONHANDLE(StackingAction); + ACTIONHANDLE(DetectorConstruction); ACTIONHANDLE(Sensitive); ACTIONHANDLE(ParticleHandler); + ACTIONHANDLE(UserInitialization); ACTIONHANDLE(GeneratorActionSequence); ACTIONHANDLE(RunActionSequence); @@ -65,94 +67,113 @@ namespace DD4hep { ACTIONHANDLE(TrackingActionSequence); ACTIONHANDLE(SteppingActionSequence); ACTIONHANDLE(StackingActionSequence); + ACTIONHANDLE(DetectorConstructionSequence); ACTIONHANDLE(PhysicsListActionSequence); ACTIONHANDLE(SensDetActionSequence); + ACTIONHANDLE(UserInitializationSequence); struct PropertyResult { - string data; - int status; - PropertyResult() : status(0) {} - PropertyResult(const string& d, int s) : data(d), status(s) {} + string data; + int status; + PropertyResult() : status(0) {} + PropertyResult(const string& d, int s) : data(d), status(s) {} PropertyResult(const PropertyResult& c) : data(c.data), status(c.status) {} - ~PropertyResult() {} - }; + ~PropertyResult() {} + }; struct Geant4ActionCreation { - template <typename H,typename T> static H cr(KernelHandle& kernel, const string& name_type) { - T action(*kernel.get(),name_type); - H handle(action.get()); - return handle; - } - static ActionHandle createAction(KernelHandle& kernel, const string& name_type) - { return cr<ActionHandle,Setup::Action>(kernel,name_type); } - static FilterHandle createFilter(KernelHandle& kernel, const string& name_type) - { return cr<FilterHandle,Setup::Filter>(kernel,name_type); } - static PhaseActionHandle createPhaseAction(KernelHandle& kernel, const string& name_type) - { return cr<PhaseActionHandle,Setup::PhaseAction>(kernel,name_type); } - static PhysicsListHandle createPhysicsList(KernelHandle& kernel, const string& name_type) - { return cr<PhysicsListHandle,Setup::PhysicsList>(kernel,name_type); } - static RunActionHandle createRunAction(KernelHandle& kernel, const string& name_type) - { return cr<RunActionHandle,Setup::RunAction>(kernel,name_type); } - static EventActionHandle createEventAction(KernelHandle& kernel, const string& name_type) - { return cr<EventActionHandle,Setup::EventAction>(kernel,name_type); } - static TrackingActionHandle createTrackingAction(KernelHandle& kernel, const string& name_type) - { return cr<TrackingActionHandle,Setup::TrackAction>(kernel,name_type); } - static SteppingActionHandle createSteppingAction(KernelHandle& kernel, const string& name_type) - { return cr<SteppingActionHandle,Setup::StepAction>(kernel,name_type); } - static StackingActionHandle createStackingAction(KernelHandle& kernel, const string& name_type) - { return cr<StackingActionHandle,Setup::StackAction>(kernel,name_type); } - static GeneratorActionHandle createGeneratorAction(KernelHandle& kernel, const string& name_type) - { return cr<GeneratorActionHandle,Setup::GenAction>(kernel,name_type); } - static SensitiveHandle createSensitive(KernelHandle& kernel, const string& name_type, const string& detector) - { return SensitiveHandle(Setup::Sensitive(*kernel.get(),name_type,detector).get()); } - static SensDetActionSequenceHandle createSensDetSequence(KernelHandle& kernel, const string& name_type) - { return cr<SensDetActionSequenceHandle,Setup::SensitiveSeq>(kernel,name_type); } - - static Geant4Action* toAction(Geant4Filter* f) { return f; } - static Geant4Action* toAction(Geant4Action* f) { return f; } - static Geant4Action* toAction(Geant4PhaseAction* f) { return f; } - static Geant4Action* toAction(Geant4Sensitive* f) { return f; } - static Geant4Action* toAction(Geant4PhysicsList* f) { return f; } - static Geant4Action* toAction(Geant4RunAction* f) { return f; } - static Geant4Action* toAction(Geant4EventAction* f) { return f; } - static Geant4Action* toAction(Geant4TrackingAction* f) { return f; } - static Geant4Action* toAction(Geant4SteppingAction* f) { return f; } - static Geant4Action* toAction(Geant4StackingAction* f) { return f; } - static Geant4Action* toAction(Geant4GeneratorAction* f) { return f; } - static Geant4Action* toAction(Geant4GeneratorActionSequence* f) { return f; } - static Geant4Action* toAction(Geant4RunActionSequence* f) { return f; } - static Geant4Action* toAction(Geant4EventActionSequence* f) { return f; } - static Geant4Action* toAction(Geant4TrackingActionSequence* f) { return f; } - static Geant4Action* toAction(Geant4SteppingActionSequence* f) { return f; } - static Geant4Action* toAction(Geant4StackingActionSequence* f) { return f; } - static Geant4Action* toAction(Geant4PhysicsListActionSequence* f){ return f; } - static Geant4Action* toAction(Geant4SensDetActionSequence* f) { return f; } - - static Geant4Action* toAction(FilterHandle f) { return f.action; } - static Geant4Action* toAction(ActionHandle f) { return f.action; } - static Geant4Action* toAction(PhaseActionHandle f) { return f.action; } - static Geant4Action* toAction(SensitiveHandle f) { return f.action; } - static Geant4Action* toAction(PhysicsListHandle f) { return f.action; } - static Geant4Action* toAction(RunActionHandle f) { return f.action; } - static Geant4Action* toAction(EventActionHandle f) { return f.action; } - static Geant4Action* toAction(TrackingActionHandle f) { return f.action; } - static Geant4Action* toAction(SteppingActionHandle f) { return f.action; } - static Geant4Action* toAction(StackingActionHandle f) { return f.action; } - static Geant4Action* toAction(GeneratorActionHandle f) { return f.action; } - static Geant4Action* toAction(GeneratorActionSequenceHandle f) { return f.action; } - static Geant4Action* toAction(RunActionSequenceHandle f) { return f.action; } - static Geant4Action* toAction(EventActionSequenceHandle f) { return f.action; } - static Geant4Action* toAction(TrackingActionSequenceHandle f) { return f.action; } - static Geant4Action* toAction(SteppingActionSequenceHandle f) { return f.action; } - static Geant4Action* toAction(StackingActionSequenceHandle f) { return f.action; } - static Geant4Action* toAction(PhysicsListActionSequenceHandle f) { return f.action; } - static Geant4Action* toAction(SensDetActionSequenceHandle f) { return f.action; } - static PropertyResult getProperty(Geant4Action* action, const string& name) { - if ( action->hasProperty(name) ) { - return PropertyResult(action->property(name).str(),1); - } - return PropertyResult("",0); - } + template <typename H,typename T> static H cr(KernelHandle& kernel, const string& name_type, bool shared) { + T action(*kernel.get(),name_type,shared); + H handle(action.get()); + return handle; + } + static ActionHandle createAction(KernelHandle& kernel, const string& name_type, bool shared) + { return cr<ActionHandle,Setup::Action>(kernel,name_type,shared); } + static FilterHandle createFilter(KernelHandle& kernel, const string& name_type, bool shared) + { return cr<FilterHandle,Setup::Filter>(kernel,name_type,shared); } + static PhaseActionHandle createPhaseAction(KernelHandle& kernel, const string& name_type, bool shared) + { return cr<PhaseActionHandle,Setup::PhaseAction>(kernel,name_type,shared); } + static PhysicsListHandle createPhysicsList(KernelHandle& kernel, const string& name_type) + { return cr<PhysicsListHandle,Setup::PhysicsList>(kernel,name_type,false); } + static RunActionHandle createRunAction(KernelHandle& kernel, const string& name_type, bool shared) + { return cr<RunActionHandle,Setup::RunAction>(kernel,name_type,shared); } + static EventActionHandle createEventAction(KernelHandle& kernel, const string& name_type, bool shared) + { return cr<EventActionHandle,Setup::EventAction>(kernel,name_type,shared); } + static TrackingActionHandle createTrackingAction(KernelHandle& kernel, const string& name_type, bool shared) + { return cr<TrackingActionHandle,Setup::TrackAction>(kernel,name_type,shared); } + static SteppingActionHandle createSteppingAction(KernelHandle& kernel, const string& name_type, bool shared) + { return cr<SteppingActionHandle,Setup::StepAction>(kernel,name_type,shared); } + static StackingActionHandle createStackingAction(KernelHandle& kernel, const string& name_type, bool shared) + { return cr<StackingActionHandle,Setup::StackAction>(kernel,name_type,shared); } + + static GeneratorActionHandle createGeneratorAction(KernelHandle& kernel, const string& name_type, bool shared) + { return cr<GeneratorActionHandle,Setup::GenAction>(kernel,name_type,shared); } + + static DetectorConstructionHandle createDetectorConstruction(KernelHandle& kernel, const string& name_type) + { return cr<DetectorConstructionHandle,Setup::DetectorConstruction>(kernel,name_type,false); } + + static UserInitializationHandle createUserInitialization(KernelHandle& kernel, const string& name_type) + { return UserInitializationHandle(Setup::Initialization(*kernel.get(),name_type,false).get());} + + static SensitiveHandle createSensitive(KernelHandle& kernel, const string& name_type, const string& detector, bool shared) + { return SensitiveHandle(Setup::Sensitive(*kernel.get(),name_type,detector,shared).get()); } + + static SensDetActionSequenceHandle createSensDetSequence(KernelHandle& kernel, const string& name_type) + { return cr<SensDetActionSequenceHandle,Setup::SensitiveSeq>(kernel,name_type,false); } + + static Geant4Action* toAction(Geant4Filter* f) { return f; } + static Geant4Action* toAction(Geant4Action* f) { return f; } + static Geant4Action* toAction(Geant4PhaseAction* f) { return f; } + static Geant4Action* toAction(Geant4Sensitive* f) { return f; } + static Geant4Action* toAction(Geant4PhysicsList* f) { return f; } + static Geant4Action* toAction(Geant4RunAction* f) { return f; } + static Geant4Action* toAction(Geant4EventAction* f) { return f; } + static Geant4Action* toAction(Geant4TrackingAction* f) { return f; } + static Geant4Action* toAction(Geant4SteppingAction* f) { return f; } + static Geant4Action* toAction(Geant4StackingAction* f) { return f; } + static Geant4Action* toAction(Geant4GeneratorAction* f) { return f; } + static Geant4Action* toAction(Geant4GeneratorActionSequence* f) { return f; } + static Geant4Action* toAction(Geant4RunActionSequence* f) { return f; } + static Geant4Action* toAction(Geant4EventActionSequence* f) { return f; } + static Geant4Action* toAction(Geant4TrackingActionSequence* f) { return f; } + static Geant4Action* toAction(Geant4SteppingActionSequence* f) { return f; } + static Geant4Action* toAction(Geant4StackingActionSequence* f) { return f; } + static Geant4Action* toAction(Geant4PhysicsListActionSequence* f){ return f; } + static Geant4Action* toAction(Geant4SensDetActionSequence* f) { return f; } + static Geant4Action* toAction(Geant4UserInitialization* f) { return f; } + static Geant4Action* toAction(Geant4UserInitializationSequence* f){ return f; } + static Geant4Action* toAction(Geant4DetectorConstruction* f) { return f; } + static Geant4Action* toAction(Geant4DetectorConstructionSequence* f){ return f; } + + static Geant4Action* toAction(FilterHandle f) { return f.action; } + static Geant4Action* toAction(ActionHandle f) { return f.action; } + static Geant4Action* toAction(PhaseActionHandle f) { return f.action; } + static Geant4Action* toAction(SensitiveHandle f) { return f.action; } + static Geant4Action* toAction(PhysicsListHandle f) { return f.action; } + static Geant4Action* toAction(RunActionHandle f) { return f.action; } + static Geant4Action* toAction(EventActionHandle f) { return f.action; } + static Geant4Action* toAction(TrackingActionHandle f) { return f.action; } + static Geant4Action* toAction(SteppingActionHandle f) { return f.action; } + static Geant4Action* toAction(StackingActionHandle f) { return f.action; } + static Geant4Action* toAction(GeneratorActionHandle f) { return f.action; } + static Geant4Action* toAction(GeneratorActionSequenceHandle f) { return f.action; } + static Geant4Action* toAction(RunActionSequenceHandle f) { return f.action; } + static Geant4Action* toAction(EventActionSequenceHandle f) { return f.action; } + static Geant4Action* toAction(TrackingActionSequenceHandle f) { return f.action; } + static Geant4Action* toAction(SteppingActionSequenceHandle f) { return f.action; } + static Geant4Action* toAction(StackingActionSequenceHandle f) { return f.action; } + static Geant4Action* toAction(PhysicsListActionSequenceHandle f) { return f.action; } + static Geant4Action* toAction(SensDetActionSequenceHandle f) { return f.action; } + static Geant4Action* toAction(UserInitializationHandle f) { return f.action; } + static Geant4Action* toAction(UserInitializationSequenceHandle f){ return f.action; } + static Geant4Action* toAction(DetectorConstructionHandle f) { return f.action; } + static Geant4Action* toAction(DetectorConstructionSequenceHandle f){ return f.action; } + static PropertyResult getProperty(Geant4Action* action, const string& name) { + if ( action->hasProperty(name) ) { + return PropertyResult(action->property(name).str(),1); + } + return PropertyResult("",0); + } static int setProperty(Geant4Action* action, const string& name, const string& value) { if ( action->hasProperty(name) ) { action->property(name).str(value); @@ -225,6 +246,9 @@ namespace { #pragma link C++ class SteppingActionHandle; #pragma link C++ class StackingActionHandle; #pragma link C++ class SensitiveHandle; +#pragma link C++ class UserInitializationHandle; +#pragma link C++ class DetectorConstructionHandle; + #pragma link C++ class GeneratorActionSequenceHandle; #pragma link C++ class RunActionSequenceHandle; #pragma link C++ class EventActionSequenceHandle; @@ -233,6 +257,8 @@ namespace { #pragma link C++ class StackingActionSequenceHandle; #pragma link C++ class PhysicsListActionSequenceHandle; #pragma link C++ class SensDetActionSequenceHandle; +#pragma link C++ class UserInitializationSequenceHandle; +#pragma link C++ class DetectorConstructionSequenceHandle; #pragma link C++ class Geant4DataDump; @@ -267,6 +293,12 @@ namespace { #pragma link C++ class Geant4PhysicsListActionSequence; #pragma link C++ class Geant4PhysicsList; +#pragma link C++ class Geant4UserInitializationSequence; +#pragma link C++ class Geant4UserInitialization; + +#pragma link C++ class Geant4DetectorConstructionSequence; +#pragma link C++ class Geant4DetectorConstruction; + #pragma link C++ class Geant4ParticleHandler; #pragma link C++ class Geant4UserParticleHandler; #pragma link C++ class Geant4Filter; diff --git a/DDG4/src/ComponentProperties.cpp b/DDG4/src/ComponentProperties.cpp index 77f61dd5d66e6531d57a61766bb45eb29b7810ea..8ecfaa6302998f62742b095a190734a5609ba100 100644 --- a/DDG4/src/ComponentProperties.cpp +++ b/DDG4/src/ComponentProperties.cpp @@ -138,6 +138,11 @@ PropertyManager::~PropertyManager() { m_properties.clear(); } +/// Export properties of another instance +void PropertyManager::adopt(const PropertyManager& copy) { + m_properties = copy.m_properties; +} + /// Check for existence bool PropertyManager::exists(const std::string& name) const { Properties::const_iterator i = m_properties.find(name); diff --git a/DDG4/src/Geant4Action.cpp b/DDG4/src/Geant4Action.cpp index b6bab52914e0ec8ef496a8dcd59ce3f4048718fa..ede1afe224ec94df0a97c9860f9c8ef0007836f3 100644 --- a/DDG4/src/Geant4Action.cpp +++ b/DDG4/src/Geant4Action.cpp @@ -43,26 +43,22 @@ TypeName TypeName::split(const string& type_name, const string& delim) { TypeName TypeName::split(const string& type_name) { return split(type_name,"/"); } - -void Geant4Action::ContextUpdate::operator()(Geant4Action* action) const { - if ( context ) { - action->m_context.setRun(context->runPtr()); - action->m_context.setEvent(context->eventPtr()); - } #if 0 - else { - action->m_context.setRun(0); - action->m_context.setEvent(0); +void Geant4Action::ContextUpdate::operator()(Geant4Action* action) const { + action->m_context = context; + if ( 0 == action->m_context ) { + + cout << "EERIOR" << endl; + } -#endif } - +#endif /// Standard constructor Geant4Action::Geant4Action(Geant4Context* ctxt, const string& nam) - : m_context(0), - m_control(0), m_outputLevel(INFO), m_needsControl(false), m_name(nam), m_refCount(1) { + : m_context(ctxt), m_control(0), m_outputLevel(INFO), m_needsControl(false), m_name(nam), + m_refCount(1) +{ InstanceCount::increment(this); - if ( ctxt ) m_context = *ctxt; m_outputLevel = ctxt ? ctxt->kernel().getOutputLevel(nam) : (printLevel()-1); declareProperty("Name", m_name); declareProperty("name", m_name); @@ -150,6 +146,10 @@ void Geant4Action::enableUI() { installMessengers(); } +/// Set or update client for the use in a new thread fiber +void Geant4Action::configureFiber(Geant4Context* /* thread_context */) { +} + /// Support for messages with variable output level using output level void Geant4Action::print(const char* fmt, ...) const { int level = outputLevel(); @@ -278,30 +278,30 @@ void Geant4Action::abortRun(const string& exception, const char* fmt, ...) const /// Access to the main run action sequence from the kernel object Geant4RunActionSequence& Geant4Action::runAction() const { - return m_context.kernel().runAction(); + return m_context->kernel().runAction(); } /// Access to the main event action sequence from the kernel object Geant4EventActionSequence& Geant4Action::eventAction() const { - return m_context.kernel().eventAction(); + return m_context->kernel().eventAction(); } /// Access to the main stepping action sequence from the kernel object Geant4SteppingActionSequence& Geant4Action::steppingAction() const { - return m_context.kernel().steppingAction(); + return m_context->kernel().steppingAction(); } /// Access to the main tracking action sequence from the kernel object Geant4TrackingActionSequence& Geant4Action::trackingAction() const { - return m_context.kernel().trackingAction(); + return m_context->kernel().trackingAction(); } /// Access to the main stacking action sequence from the kernel object Geant4StackingActionSequence& Geant4Action::stackingAction() const { - return m_context.kernel().stackingAction(); + return m_context->kernel().stackingAction(); } /// Access to the main generator action sequence from the kernel object Geant4GeneratorActionSequence& Geant4Action::generatorAction() const { - return m_context.kernel().generatorAction(); + return m_context->kernel().generatorAction(); } diff --git a/DDG4/src/Geant4Converter.cpp b/DDG4/src/Geant4Converter.cpp index 04cf9004dc22782b1b33fb5372ceef41b619c16e..12a09961e9bc388fea14213b6d2807a09a7a3a6f 100644 --- a/DDG4/src/Geant4Converter.cpp +++ b/DDG4/src/Geant4Converter.cpp @@ -52,13 +52,11 @@ #include "TMath.h" // Geant4 include files -#include "G4VSensitiveDetector.hh" #include "G4VisAttributes.hh" #include "G4ProductionCuts.hh" #include "G4VUserRegionInformation.hh" #include "G4Element.hh" -#include "G4SDManager.hh" #include "G4Box.hh" #include "G4Trd.hh" #include "G4Tubs.hh" @@ -95,10 +93,9 @@ #include <sstream> using namespace DD4hep::Simulation; -using namespace DD4hep::Simulation::Geant4GeometryMaps; +//using namespace DD4hep::Simulation::Geant4GeometryMaps; using namespace DD4hep::Geometry; using namespace DD4hep; -using namespace CLHEP; using namespace std; #include "DDG4/Geant4AssemblyVolume.h" @@ -126,13 +123,13 @@ void Geant4AssemblyVolume::imprint(Geant4GeometryInfo& info, unsigned int numberOfDaughters; if( copyNumBase == 0 ) - { - numberOfDaughters = pMotherLV->GetNoDaughters(); - } + { + numberOfDaughters = pMotherLV->GetNoDaughters(); + } else - { - numberOfDaughters = copyNumBase; - } + { + numberOfDaughters = copyNumBase; + } // We start from the first available index // @@ -156,58 +153,58 @@ void Geant4AssemblyVolume::imprint(Geant4GeometryInfo& info, G4Transform3D Tfinal = transformation * Ta; if ( triplets[i].GetVolume() ) - { - // Generate the unique name for the next PV instance - // The name has format: - // - // av_WWW_impr_XXX_YYY_ZZZ - // where the fields mean: - // WWW - assembly volume instance number - // XXX - assembly volume imprint number - // YYY - the name of a log. volume we want to make a placement of - // ZZZ - the log. volume index inside the assembly volume - // - std::stringstream pvName; - pvName << "av_" - << GetAssemblyID() - << "_impr_" - << GetImprintsCount() - << "_" - << triplets[i].GetVolume()->GetName().c_str() - << "_pv_" - << i - << std::ends; - - // Generate a new physical volume instance inside a mother - // (as we allow 3D transformation use G4ReflectionFactory to - // take into account eventual reflection) - // - G4PhysicalVolumesPair pvPlaced - = G4ReflectionFactory::Instance()->Place( Tfinal, - pvName.str().c_str(), - triplets[i].GetVolume(), - pMotherLV, - false, - numberOfDaughters + i, - surfCheck ); - - // Register the physical volume created by us so we can delete it later - // - fPVStore.push_back( pvPlaced.first ); - info.g4VolumeImprints[vol].push_back(make_pair(new_chain,pvPlaced.first)); + { + // Generate the unique name for the next PV instance + // The name has format: + // + // av_WWW_impr_XXX_YYY_ZZZ + // where the fields mean: + // WWW - assembly volume instance number + // XXX - assembly volume imprint number + // YYY - the name of a log. volume we want to make a placement of + // ZZZ - the log. volume index inside the assembly volume + // + std::stringstream pvName; + pvName << "av_" + << GetAssemblyID() + << "_impr_" + << GetImprintsCount() + << "_" + << triplets[i].GetVolume()->GetName().c_str() + << "_pv_" + << i + << std::ends; + + // Generate a new physical volume instance inside a mother + // (as we allow 3D transformation use G4ReflectionFactory to + // take into account eventual reflection) + // + G4PhysicalVolumesPair pvPlaced + = G4ReflectionFactory::Instance()->Place( Tfinal, + pvName.str().c_str(), + triplets[i].GetVolume(), + pMotherLV, + false, + numberOfDaughters + i, + surfCheck ); + + // Register the physical volume created by us so we can delete it later + // + fPVStore.push_back( pvPlaced.first ); + info.g4VolumeImprints[vol].push_back(make_pair(new_chain,pvPlaced.first)); #if 0 - cout << " Assembly:Parent:" << parent->GetName() << " " << node->GetName() - << " " << (void*)node << " G4:" << pvName.str() << " Daughter:" - << DetectorTools::placementPath(new_chain) << endl; - cout << endl; + cout << " Assembly:Parent:" << parent->GetName() << " " << node->GetName() + << " " << (void*)node << " G4:" << pvName.str() << " Daughter:" + << DetectorTools::placementPath(new_chain) << endl; + cout << endl; #endif - if ( pvPlaced.second ) { - G4Exception("G4AssemblyVolume::MakeImprint(..)", "GeomVol0003", FatalException, - "Fancy construct popping new mother from the stack!"); - //fPVStore.push_back( pvPlaced.second ); - } + if ( pvPlaced.second ) { + G4Exception("G4AssemblyVolume::MakeImprint(..)", "GeomVol0003", FatalException, + "Fancy construct popping new mother from the stack!"); + //fPVStore.push_back( pvPlaced.second ); } + } else if ( triplets[i].GetAssembly() ) { // Place volumes in this assembly with composed transformation imprint(info, parent, new_chain, (Geant4AssemblyVolume*)triplets[i].GetAssembly(), pMotherLV, Tfinal, i*100+copyNumBase, surfCheck ); @@ -266,7 +263,7 @@ namespace { /// Initializing Constructor Geant4Converter::Geant4Converter(LCDD& lcdd_ref) -: Geant4Mapping(lcdd_ref), m_checkOverlaps(true) { + : Geant4Mapping(lcdd_ref), m_checkOverlaps(true) { this->Geant4Mapping::init(); m_propagateRegions = true; m_outputLevel = PrintLevel(printLevel() - 1); @@ -274,7 +271,7 @@ Geant4Converter::Geant4Converter(LCDD& lcdd_ref) /// Initializing Constructor Geant4Converter::Geant4Converter(LCDD& lcdd_ref, PrintLevel level) -: Geant4Mapping(lcdd_ref), m_checkOverlaps(true) { + : Geant4Mapping(lcdd_ref), m_checkOverlaps(true) { this->Geant4Mapping::init(); m_propagateRegions = true; m_outputLevel = level; @@ -319,12 +316,12 @@ void* Geant4Converter::handleMaterial(const string& name, Material medium) const if (!mat) { mat = G4Material::GetMaterial(name, false); if (!mat) { - TGeoMaterial* m = medium->GetMaterial(); + TGeoMaterial* material = medium->GetMaterial(); G4State state = kStateUndefined; - double density = m->GetDensity() * (CLHEP::gram / CLHEP::cm3); + double density = material->GetDensity() * (CLHEP::gram / CLHEP::cm3); if (density < 1e-25) density = 1e-25; - switch (m->GetState()) { + switch (material->GetState()) { case TGeoMaterial::kMatStateSolid: state = kStateSolid; break; @@ -339,12 +336,13 @@ void* Geant4Converter::handleMaterial(const string& name, Material medium) const state = kStateUndefined; break; } - if (m->IsMixture()) { + if (material->IsMixture()) { double A_total = 0.0; double W_total = 0.0; - TGeoMixture* mix = (TGeoMixture*) m; + TGeoMixture* mix = (TGeoMixture*) material; int nElements = mix->GetNelements(); - mat = new G4Material(name, density, nElements, state, m->GetTemperature(), m->GetPressure()); + mat = new G4Material(name, density, nElements, state, + material->GetTemperature(), material->GetPressure()); for (int i = 0; i < nElements; ++i) { A_total += (mix->GetAmixt())[i]; W_total += (mix->GetWmixt())[i]; @@ -362,10 +360,11 @@ void* Geant4Converter::handleMaterial(const string& name, Material medium) const } } else { - double z = m->GetZ(), a = m->GetA(); + double z = material->GetZ(), a = material->GetA(); if ( z < 1.0000001 ) z = 1.0; if ( a < 0.5000001 ) a = 1.0; - mat = new G4Material(name, z, a, density, state, m->GetTemperature(), m->GetPressure()); + mat = new G4Material(name, z, a, density, state, + material->GetTemperature(), material->GetPressure()); } stringstream str; str << (*mat); @@ -504,28 +503,28 @@ void* Geant4Converter::handleSolid(const string& name, const TGeoShape* shape) c TGeoShape* ls = boolean->GetLeftShape(); TGeoShape* rs = boolean->GetRightShape(); if (strcmp(ls->ClassName(), "TGeoScaledShape") == 0 && - strcmp(rs->ClassName(), "TGeoBBox") == 0) { - if (strcmp(((TGeoScaledShape *)ls)->GetShape()->ClassName(), "TGeoSphere") == 0) { - if (oper == TGeoBoolNode::kGeoIntersection) { - TGeoScaledShape* lls = (TGeoScaledShape *)ls; - TGeoBBox* rrs = (TGeoBBox*)rs; - double sx = lls->GetScale()->GetScale()[0]; - double sy = lls->GetScale()->GetScale()[1]; - double radius = ((TGeoSphere *)lls->GetShape())->GetRmax(); - double dz = rrs->GetDZ(); - double zorig = rrs->GetOrigin()[2]; - double zcut2 = dz + zorig; - double zcut1 = 2 * zorig - zcut2; - solid = new G4Ellipsoid(name, - sx * radius * CM_2_MM, - sy * radius * CM_2_MM, - radius * CM_2_MM, - zcut1 * CM_2_MM, - zcut2 * CM_2_MM); - data().g4Solids[shape] = solid; - return solid; - } - } + strcmp(rs->ClassName(), "TGeoBBox") == 0) { + if (strcmp(((TGeoScaledShape *)ls)->GetShape()->ClassName(), "TGeoSphere") == 0) { + if (oper == TGeoBoolNode::kGeoIntersection) { + TGeoScaledShape* lls = (TGeoScaledShape *)ls; + TGeoBBox* rrs = (TGeoBBox*)rs; + double sx = lls->GetScale()->GetScale()[0]; + double sy = lls->GetScale()->GetScale()[1]; + double radius = ((TGeoSphere *)lls->GetShape())->GetRmax(); + double dz = rrs->GetDZ(); + double zorig = rrs->GetOrigin()[2]; + double zcut2 = dz + zorig; + double zcut1 = 2 * zorig - zcut2; + solid = new G4Ellipsoid(name, + sx * radius * CM_2_MM, + sy * radius * CM_2_MM, + radius * CM_2_MM, + zcut1 * CM_2_MM, + zcut2 * CM_2_MM); + data().g4Solids[shape] = solid; + return solid; + } + } } if (m->IsRotation()) { @@ -561,7 +560,7 @@ void* Geant4Converter::handleSolid(const string& name, const TGeoShape* shape) c /// Dump logical volume in GDML format to output stream void* Geant4Converter::handleVolume(const string& name, const TGeoVolume* volume) const { Geant4GeometryInfo& info = data(); - VolumeMap::const_iterator volIt = info.g4Volumes.find(volume); + Geant4GeometryMaps::VolumeMap::const_iterator volIt = info.g4Volumes.find(volume); if (volIt == info.g4Volumes.end() ) { const TGeoVolume* v = volume; Volume _v = Ref_t(v); @@ -572,17 +571,6 @@ void* Geant4Converter::handleVolume(const string& name, const TGeoVolume* volume G4Material* medium = 0; bool assembly = s->IsA() == TGeoShapeAssembly::Class() || v->IsA() == TGeoVolumeAssembly::Class(); - SensitiveDetector det = _v.sensitiveDetector(); - G4VSensitiveDetector* sd = 0; - - if (det.isValid()) { - sd = info.g4SensDets[det.ptr()]; - if (!sd) { - throw runtime_error("G4Cnv::volume[" + name + "]: + FATAL Failed to " - "access Geant4 sensitive detector."); - } - sd->Activate(true); - } LimitSet lim = _v.limitSet(); G4UserLimits* user_limits = 0; if (lim.isValid()) { @@ -607,8 +595,8 @@ void* Geant4Converter::handleVolume(const string& name, const TGeoVolume* volume } } PrintLevel lvl = m_outputLevel; //string(det.name())=="SiTrackerBarrel" ? WARNING : m_outputLevel; - printout(lvl, "Geant4Converter", "++ Convert Volume %-32s: %p %s/%s assembly:%s sensitive:%s", n.c_str(), v, - s->IsA()->GetName(), v->IsA()->GetName(), yes_no(assembly), yes_no(det.isValid())); + printout(lvl, "Geant4Converter", "++ Convert Volume %-32s: %p %s/%s assembly:%s", + n.c_str(), v, s->IsA()->GetName(), v->IsA()->GetName(), yes_no(assembly)); if (assembly) { //info.g4AssemblyVolumes[v] = new Geant4AssemblyVolume(); @@ -622,21 +610,19 @@ void* Geant4Converter::handleVolume(const string& name, const TGeoVolume* volume throw runtime_error("G4Converter: No Geant4 material present for volume:" + n); } if (user_limits) { - printout(m_outputLevel, "Geant4Converter", "++ Volume + Apply LIMITS settings:%-24s to volume %s.", lim.name(), _v.name()); + printout(m_outputLevel, "Geant4Converter", "++ Volume + Apply LIMITS settings:%-24s to volume %s.", + lim.name(), _v.name()); } - G4LogicalVolume* vol = new G4LogicalVolume(solid, medium, n, 0, sd, user_limits); + G4LogicalVolume* vol = new G4LogicalVolume(solid, medium, n, 0, 0, user_limits); if (region) { - printout(m_outputLevel, "Geant4Converter", "++ Volume + Apply REGION settings: %s to volume %s.", reg.name(), _v.name()); + printout(m_outputLevel, "Geant4Converter", "++ Volume + Apply REGION settings: %s to volume %s.", + reg.name(), _v.name()); vol->SetRegion(region); region->AddRootLogicalVolume(vol); } if (vis_attr) { vol->SetVisAttributes(vis_attr); } - if (sd) { - printout(m_outputLevel, "Geant4Converter", "++ Volume: + %s <> %s Solid:%s Mat:%s SD:%s", name.c_str(), vol->GetName().c_str(), - solid->GetName().c_str(), medium->GetName().c_str(), sd->GetName().c_str()); - } info.g4Volumes[v] = vol; printout(m_outputLevel, "Geant4Converter", "++ Volume + %s converted: %p ---> G4: %p", n.c_str(), v, vol); } @@ -678,7 +664,7 @@ void* Geant4Converter::handleAssembly(const std::string& name, const TGeoNode* n TGeoMatrix* tr = d->GetMatrix(); MyTransform3D transform(tr->GetTranslation(),tr->IsRotation() ? tr->GetRotationMatrix() : s_identity_rot); if ( dau_vol->IsA() == TGeoVolumeAssembly::Class() ) { - AssemblyMap::iterator assIt = info.g4AssemblyVolumes.find(d); + Geant4GeometryMaps::AssemblyMap::iterator assIt = info.g4AssemblyVolumes.find(d); if ( assIt == info.g4AssemblyVolumes.end() ) { printout(FATAL, "Geant4Converter", "+++ Invalid child assembly at %s : %d parent: %s child:%s", __FILE__, __LINE__, name.c_str(), d->GetName()); @@ -690,7 +676,7 @@ void* Geant4Converter::handleAssembly(const std::string& name, const TGeoNode* n transform.dx(), transform.dy(), transform.dz()); } else { - VolumeMap::iterator volIt = info.g4Volumes.find(dau_vol); + Geant4GeometryMaps::VolumeMap::iterator volIt = info.g4Volumes.find(dau_vol); if ( volIt == info.g4Volumes.end() ) { printout(FATAL, "Geant4Converter", "+++ Invalid child volume at %s : %d parent: %s child:%s", __FILE__, __LINE__, name.c_str(), d->GetName()); @@ -710,7 +696,7 @@ void* Geant4Converter::handleAssembly(const std::string& name, const TGeoNode* n /// Dump volume placement in GDML format to output stream void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node) const { Geant4GeometryInfo& info = data(); - PlacementMap::const_iterator g4it = info.g4Placements.find(node); + Geant4GeometryMaps::PlacementMap::const_iterator g4it = info.g4Placements.find(node); G4VPhysicalVolume* g4 = (g4it == info.g4Placements.end()) ? 0 : (*g4it).second; if (!g4) { TGeoVolume* mot_vol = node->GetMotherVolume(); @@ -729,7 +715,7 @@ void* Geant4Converter::handlePlacement(const string& name, const TGeoNode* node) bool node_is_assembly = vol->IsA() == TGeoVolumeAssembly::Class(); bool mother_is_assembly = mot_vol ? mot_vol->IsA() == TGeoVolumeAssembly::Class() : false; MyTransform3D transform(tr->GetTranslation(),tr->IsRotation() ? tr->GetRotationMatrix() : s_identity_rot); - VolumeMap::const_iterator volIt = info.g4Volumes.find(mot_vol); + Geant4GeometryMaps::VolumeMap::const_iterator volIt = info.g4Volumes.find(mot_vol); if ( mother_is_assembly ) { // @@ -805,8 +791,8 @@ void* Geant4Converter::handleRegion(Region region, const set<const TGeoVolume*>& LimitSet ls = m_lcdd.limitSet(nam); if (ls.isValid()) { bool found = false; - const LimitMap& lm = data().g4Limits; - for (LimitMap::const_iterator j = lm.begin(); j != lm.end(); ++j) { + const Geant4GeometryMaps::LimitMap& lm = data().g4Limits; + for (Geant4GeometryMaps::LimitMap::const_iterator j = lm.begin(); j != lm.end(); ++j) { if (nam == (*j).first->GetName()) { g4->SetUserLimits((*j).second); found = true; @@ -850,35 +836,6 @@ void* Geant4Converter::handleLimitSet(LimitSet limitset, const set<const TGeoVol return g4; } -/// Convert the geometry type SensitiveDetector into the corresponding Geant4 object(s). -void* Geant4Converter::handleSensitive(SensitiveDetector sens_det, const set<const TGeoVolume*>& /* volumes */) const { - Geant4GeometryInfo& info = data(); - G4VSensitiveDetector* g4 = info.g4SensDets[sens_det]; - if (!g4) { - SensitiveDetector sd = Ref_t(sens_det); - string type = sd.type(), name = sd.name(); - g4 = PluginService::Create<G4VSensitiveDetector*>(type, name, &m_lcdd); - if (!g4) { - string tmp = type; - tmp[0] = ::toupper(tmp[0]); - type = "Geant4" + tmp; - g4 = PluginService::Create<G4VSensitiveDetector*>(type, name, &m_lcdd); - if (!g4) { - PluginDebug dbg; - g4 = PluginService::Create<G4VSensitiveDetector*>(type, name, &m_lcdd); - if ( !g4 ) { - throw runtime_error("Geant4Converter<SensitiveDetector>: FATAL Failed to " - "create Geant4 sensitive detector factory " + name + " of type " + type + "."); - } - } - } - g4->Activate(true); - G4SDManager::GetSDMpointer()->AddNewDetector(g4); - info.g4SensDets[sens_det] = g4; - } - return g4; -} - /// Convert the geometry visualisation attributes to the corresponding Geant4 object(s). void* Geant4Converter::handleVis(const string& /* name */, VisAttr attr) const { Geant4GeometryInfo& info = data(); @@ -946,9 +903,8 @@ void Geant4Converter::handleProperties(LCDD::Properties& prp) const { } /// Convert the geometry type SensitiveDetector into the corresponding Geant4 object(s). -void* Geant4Converter::printSensitive(SensitiveDetector sens_det, const set<const TGeoVolume*>& /* volumes */) const { +void Geant4Converter::printSensitive(SensitiveDetector sens_det, const set<const TGeoVolume*>& /* volumes */) const { Geant4GeometryInfo& info = data(); - G4VSensitiveDetector* g4 = info.g4SensDets[sens_det]; ConstVolumeSet& volset = info.sensitives[sens_det]; SensitiveDetector sd = Ref_t(sens_det); stringstream str; @@ -972,7 +928,6 @@ void* Geant4Converter::printSensitive(SensitiveDetector sens_det, const set<cons << vol->GetNoDaughters() << " daughters."; printout(INFO, "Geant4Converter", str.str().c_str()); } - return g4; } string printSolid(G4VSolid* sol) { @@ -1066,8 +1021,6 @@ Geant4Converter& Geant4Converter::create(DetElement top) { printout(m_outputLevel, "Geant4Converter", "++ Handled %ld solids.", geo.solids.size()); handleRefs(this, geo.vis, &Geant4Converter::handleVis); printout(m_outputLevel, "Geant4Converter", "++ Handled %ld visualization attributes.", geo.vis.size()); - handleMap(this, geo.sensitives, &Geant4Converter::handleSensitive); - printout(m_outputLevel, "Geant4Converter", "++ Handled %ld sensitive detectors.", geo.sensitives.size()); handleMap(this, geo.limits, &Geant4Converter::handleLimitSet); printout(m_outputLevel, "Geant4Converter", "++ Handled %ld limit sets.", geo.limits.size()); handleMap(this, geo.regions, &Geant4Converter::handleRegion); diff --git a/DDG4/src/Geant4DetectorConstruction.cpp b/DDG4/src/Geant4DetectorConstruction.cpp index bd5bbea5fc353b2a9617b71ba00f15a79742b79b..8715ca3c1358d51f4c5a24c424458a131e103fed 100644 --- a/DDG4/src/Geant4DetectorConstruction.cpp +++ b/DDG4/src/Geant4DetectorConstruction.cpp @@ -13,137 +13,156 @@ //========================================================================== // Framework include files +#include "DD4hep/InstanceCount.h" +#include "DDG4/Geant4Mapping.h" +#include "DDG4/Geant4GeometryInfo.h" #include "DDG4/Geant4DetectorConstruction.h" -#include "DDG4/Geant4HierarchyDump.h" -#include "DDG4/Geant4Converter.h" -#include "DDG4/Geant4Kernel.h" -#include "DD4hep/LCDD.h" -#include "TGeoManager.h" -#include "G4PVPlacement.hh" - -// C/C++ include files -#include <iostream> - -#ifdef GEANT4_HAS_GDML -#include "G4GDMLParser.hh" -#endif +#include "G4VUserDetectorConstruction.hh" +#include "G4SDManager.hh" using namespace std; using namespace DD4hep; using namespace DD4hep::Simulation; -namespace { - static Geant4DetectorConstruction* s_instance = 0; +/// Helper: Assign sensitive detector to logical volume +void Geant4DetectorConstructionContext::setSensitiveDetector(G4LogicalVolume* vol, G4VSensitiveDetector* sd) { + //detector->SetSensitiveDetector(vol,sd); + G4SDManager::GetSDMpointer()->AddNewDetector(sd); + vol->SetSensitiveDetector(sd); +} + +/// Standard Constructor +Geant4DetectorConstruction::Geant4DetectorConstruction(Geant4Context* ctxt, const std::string& nam) + : Geant4Action(ctxt,nam) +{ } -/// Instance accessor -Geant4DetectorConstruction* Geant4DetectorConstruction::instance(Geant4Kernel& kernel) { - if ( 0 == s_instance ) s_instance = new Geant4DetectorConstruction(kernel); - return s_instance; +/// Default destructor +Geant4DetectorConstruction::~Geant4DetectorConstruction() { } -/// Initializing constructor for other clients -Geant4DetectorConstruction::Geant4DetectorConstruction(Geometry::LCDD& lcdd) - : Geant4Action(0,"DetectorConstruction"), m_lcdd(lcdd), m_world(0) -{ - m_outputLevel = PrintLevel(printLevel()-1); - s_instance = this; +/// Geometry construction callback. Called at "Construct()" +void Geant4DetectorConstruction::constructGeo(Geant4DetectorConstructionContext* ) { } -/// Initializing constructor for DDG4 -Geant4DetectorConstruction::Geant4DetectorConstruction(Geant4Kernel& kernel) - : Geant4Action(0,"DetectorConstruction"), m_lcdd(kernel.lcdd()), m_world(0) +/// Electromagnetic field construction callback. Called at "ConstructSDandField()" +void Geant4DetectorConstruction::constructField(Geant4DetectorConstructionContext* ) { +} + +/// Sensitive detector construction callback. Called at "ConstructSDandField()" +void Geant4DetectorConstruction::constructSensitives(Geant4DetectorConstructionContext* ) { +} + + +/// Standard Constructor +Geant4DetectorConstructionSequence::Geant4DetectorConstructionSequence(Geant4Context* ctxt, const std::string& nam) + : Geant4Action(ctxt,nam) { - m_outputLevel = kernel.getOutputLevel("Geant4Converter"); - s_instance = this; + m_needsControl = true; + InstanceCount::increment(this); } /// Default destructor -Geant4DetectorConstruction::~Geant4DetectorConstruction() { - s_instance = 0; -} - -G4VPhysicalVolume* Geant4DetectorConstruction::Construct() { - Geant4Mapping& g4map = Geant4Mapping::instance(); - Geometry::DetElement world = m_lcdd.world(); - Geant4Converter conv(m_lcdd, m_outputLevel); - Geant4GeometryInfo* geo_info = conv.create(world).detach(); - g4map.attach(geo_info); - m_world = geo_info->world(); - m_lcdd.apply("DD4hepVolumeManager", 0, 0); - // Create Geant4 volume manager - g4map.volumeManager(); - //Geant4HierarchyDump dmp(m_lcdd); - //dmp.dump("",m_world); -#ifdef GEANT4_HAS_GDML - if ( ::getenv("DUMP_GDML") ) { - G4GDMLParser parser; - parser.Write("detector.gdml",m_world); +Geant4DetectorConstructionSequence::~Geant4DetectorConstructionSequence() { + m_actors(&Geant4DetectorConstruction::release); + InstanceCount::decrement(this); +} + +/// Set or update client context +void Geant4DetectorConstructionSequence::updateContext(Geant4Context* ctxt) { + m_context = ctxt; + m_actors(&Geant4DetectorConstruction::updateContext,ctxt); +} + +/// Add an actor responding to all callbacks. Sequence takes ownership. +void Geant4DetectorConstructionSequence::adopt(Geant4DetectorConstruction* action) { + if (action) { + action->addRef(); + m_actors.add(action); + return; } -#endif - return m_world; + throw runtime_error("Geant4RunActionSequence: Attempt to add invalid actor!"); +} + +/// Geometry construction callback. Called at "Construct()" +void Geant4DetectorConstructionSequence::constructGeo(Geant4DetectorConstructionContext* ctxt) { + m_actors(&Geant4DetectorConstruction::constructGeo, ctxt); +} + +/// Electromagnetic field construction callback. Called at "ConstructSDandField()" +void Geant4DetectorConstructionSequence::constructField(Geant4DetectorConstructionContext* ctxt) { + m_actors(&Geant4DetectorConstruction::constructField, ctxt); +} + +/// Sensitive detector construction callback. Called at "ConstructSDandField()" +void Geant4DetectorConstructionSequence::constructSensitives(Geant4DetectorConstructionContext* ctxt) { + m_actors(&Geant4DetectorConstruction::constructSensitives, ctxt); } /// Access to the converted regions -const Geant4GeometryMaps::RegionMap& Geant4DetectorConstruction::regions() const { +const Geant4GeometryMaps::RegionMap& Geant4DetectorConstructionSequence::regions() const { Geant4GeometryInfo* p = Geant4Mapping::instance().ptr(); if ( p ) return p->g4Regions; - throw runtime_error("+++ Geant4DetectorConstruction::regions: Access not possible. Geometry is not yet converted!"); + throw runtime_error("+++ Geant4DetectorConstructionSequence::regions: Access not possible. Geometry is not yet converted!"); } - +#if 0 /// Access to the converted sensitive detectors -const Geant4GeometryMaps::SensDetMap& Geant4DetectorConstruction::sensitives() const { +const Geant4GeometryMaps::SensDetMap& Geant4DetectorConstructionSequence::sensitives() const { Geant4GeometryInfo* p = Geant4Mapping::instance().ptr(); if ( p ) return p->g4SensDets; - throw runtime_error("+++ Geant4DetectorConstruction::sensitives: Access not possible. Geometry is not yet converted!"); + throw runtime_error("+++ Geant4DetectorConstructionSequence::sensitives: Access not possible. Geometry is not yet converted!"); } - +#endif /// Access to the converted volumes -const Geant4GeometryMaps::VolumeMap& Geant4DetectorConstruction::volumes() const { +const Geant4GeometryMaps::VolumeMap& Geant4DetectorConstructionSequence::volumes() const { Geant4GeometryInfo* p = Geant4Mapping::instance().ptr(); if ( p ) return p->g4Volumes; - throw runtime_error("+++ Geant4DetectorConstruction::volumes: Access not possible. Geometry is not yet converted!"); + throw runtime_error("+++ Geant4DetectorConstructionSequence::volumes: Access not possible. Geometry is not yet converted!"); } /// Access to the converted shapes -const Geant4GeometryMaps::SolidMap& Geant4DetectorConstruction::shapes() const { +const Geant4GeometryMaps::SolidMap& Geant4DetectorConstructionSequence::shapes() const { Geant4GeometryInfo* p = Geant4Mapping::instance().ptr(); if ( p ) return p->g4Solids; - throw runtime_error("+++ Geant4DetectorConstruction::shapes: Access not possible. Geometry is not yet converted!"); + throw runtime_error("+++ Geant4DetectorConstructionSequence::shapes: Access not possible. Geometry is not yet converted!"); } /// Access to the converted limit sets -const Geant4GeometryMaps::LimitMap& Geant4DetectorConstruction::limits() const { +const Geant4GeometryMaps::LimitMap& Geant4DetectorConstructionSequence::limits() const { Geant4GeometryInfo* p = Geant4Mapping::instance().ptr(); if ( p ) return p->g4Limits; - throw runtime_error("+++ Geant4DetectorConstruction::limits: Access not possible. Geometry is not yet converted!"); + throw runtime_error("+++ Geant4DetectorConstructionSequence::limits: Access not possible. Geometry is not yet converted!"); } /// Access to the converted assemblies -const Geant4GeometryMaps::AssemblyMap& Geant4DetectorConstruction::assemblies() const { +const Geant4GeometryMaps::AssemblyMap& Geant4DetectorConstructionSequence::assemblies() const { Geant4GeometryInfo* p = Geant4Mapping::instance().ptr(); if ( p ) return p->g4AssemblyVolumes; - throw runtime_error("+++ Geant4DetectorConstruction::assemblies: Access not possible. Geometry is not yet converted!"); + throw runtime_error("+++ Geant4DetectorConstructionSequence::assemblies: Access not possible. Geometry is not yet converted!"); } /// Access to the converted placements -const Geant4GeometryMaps::PlacementMap& Geant4DetectorConstruction::placements() const { +const Geant4GeometryMaps::PlacementMap& Geant4DetectorConstructionSequence::placements() const { Geant4GeometryInfo* p = Geant4Mapping::instance().ptr(); if ( p ) return p->g4Placements; - throw runtime_error("+++ Geant4DetectorConstruction::placements: Access not possible. Geometry is not yet converted!"); + throw runtime_error("+++ Geant4DetectorConstructionSequence::placements: Access not possible. Geometry is not yet converted!"); } /// Access to the converted materials -const Geant4GeometryMaps::MaterialMap& Geant4DetectorConstruction::materials() const { +const Geant4GeometryMaps::MaterialMap& Geant4DetectorConstructionSequence::materials() const { Geant4GeometryInfo* p = Geant4Mapping::instance().ptr(); if ( p ) return p->g4Materials; - throw runtime_error("+++ Geant4DetectorConstruction::materials: Access not possible. Geometry is not yet converted!"); + throw runtime_error("+++ Geant4DetectorConstructionSequence::materials: Access not possible. Geometry is not yet converted!"); } /// Access to the converted elements -const Geant4GeometryMaps::ElementMap& Geant4DetectorConstruction::elements() const { +const Geant4GeometryMaps::ElementMap& Geant4DetectorConstructionSequence::elements() const { Geant4GeometryInfo* p = Geant4Mapping::instance().ptr(); if ( p ) return p->g4Elements; - throw runtime_error("+++ Geant4DetectorConstruction::elements: Access not possible. Geometry is not yet converted!"); + throw runtime_error("+++ Geant4DetectorConstructionSequence::elements: Access not possible. Geometry is not yet converted!"); } + + + + diff --git a/DDG4/src/Geant4EventAction.cpp b/DDG4/src/Geant4EventAction.cpp index 01e3c763cf7bf59ac1a25fc6c822e6b77cad10e7..b4ec0cab4287578d9c0122fb900af695df8d11c3 100644 --- a/DDG4/src/Geant4EventAction.cpp +++ b/DDG4/src/Geant4EventAction.cpp @@ -15,15 +15,23 @@ // Framework include files #include "DD4hep/InstanceCount.h" #include "DDG4/Geant4EventAction.h" +// Geant4 headers +#include "G4Threading.hh" +#include "G4AutoLock.hh" // C/C++ include files #include <stdexcept> using namespace std; using namespace DD4hep::Simulation; +namespace { + G4Mutex event_action_mutex=G4MUTEX_INITIALIZER; +} + /// Standard constructor Geant4EventAction::Geant4EventAction(Geant4Context* ctxt, const string& nam) - : Geant4Action(ctxt, nam) { + : Geant4Action(ctxt, nam) +{ InstanceCount::increment(this); } @@ -33,11 +41,60 @@ Geant4EventAction::~Geant4EventAction() { } /// begin-of-event callback -void Geant4EventAction::begin(const G4Event*) { +void Geant4EventAction::begin(const G4Event* ) { +} + +/// End-of-event callback +void Geant4EventAction::end(const G4Event* ) { +} + +/// Standard constructor +Geant4SharedEventAction::Geant4SharedEventAction(Geant4Context* ctxt, const string& nam) + : Geant4EventAction(ctxt, nam) +{ + InstanceCount::increment(this); +} + +/// Default destructor +Geant4SharedEventAction::~Geant4SharedEventAction() { + releasePtr(m_action); + InstanceCount::decrement(this); +} + +/// Set or update client for the use in a new thread fiber +void Geant4SharedEventAction::configureFiber(Geant4Context* thread_context) { + m_action->configureFiber(thread_context); +} + +/// Underlying object to be used during the execution of this thread +void Geant4SharedEventAction::use(Geant4EventAction* action) { + if (action) { + action->addRef(); + m_properties.adopt(action->properties()); + m_action = action; + return; + } + throw runtime_error("Geant4SharedEventAction: Attempt to use invalid actor!"); +} + +/// Begin-of-event callback +void Geant4SharedEventAction::begin(const G4Event* event) { + if ( m_action ) { + G4AutoLock protection_lock(&event_action_mutex); { + ContextSwap swap(m_action,context()); + m_action->begin(event); + } + } } /// End-of-event callback -void Geant4EventAction::end(const G4Event*) { +void Geant4SharedEventAction::end(const G4Event* event) { + if ( m_action ) { + G4AutoLock protection_lock(&event_action_mutex); { + ContextSwap swap(m_action,context()); + m_action->end(event); + } + } } /// Standard constructor @@ -57,9 +114,26 @@ Geant4EventActionSequence::~Geant4EventActionSequence() { InstanceCount::decrement(this); } +/// Set or update client context +void Geant4EventActionSequence::updateContext(Geant4Context* ctxt) { + m_context = ctxt; + m_actors.updateContext(ctxt); +} + +/// Set or update client for the use in a new thread fiber +void Geant4EventActionSequence::configureFiber(Geant4Context* thread_context) { + m_actors(&Geant4Action::configureFiber, thread_context); +} + +/// Get an action by name +Geant4EventAction* Geant4EventActionSequence::get(const string& nam) const { + return m_actors.get(FindByName(TypeName::split(nam).second)); +} + /// Add an actor responding to all callbacks. Sequence takes ownership. void Geant4EventActionSequence::adopt(Geant4EventAction* action) { if (action) { + G4AutoLock protection_lock(&event_action_mutex); action->addRef(); m_actors.add(action); return; @@ -68,16 +142,14 @@ void Geant4EventActionSequence::adopt(Geant4EventAction* action) { } /// Pre-track action callback -void Geant4EventActionSequence::begin(const G4Event* event) { - m_actors(ContextUpdate(context())); +void Geant4EventActionSequence::begin(const G4Event* event) { m_actors(&Geant4EventAction::begin, event); m_begin(event); } /// Post-track action callback -void Geant4EventActionSequence::end(const G4Event* event) { +void Geant4EventActionSequence::end(const G4Event* event) { m_end(event); m_actors(&Geant4EventAction::end, event); m_final(event); - m_actors(ContextUpdate()); } diff --git a/DDG4/src/Geant4Exec.cpp b/DDG4/src/Geant4Exec.cpp index 5c94ec6061bb56a5c41ce3b99ba6ea88b5314eb7..a49ba203d9ea904a51f406e13b52101a934f0467 100644 --- a/DDG4/src/Geant4Exec.cpp +++ b/DDG4/src/Geant4Exec.cpp @@ -23,13 +23,15 @@ #include "DDG4/Geant4TrackingAction.h" #include "DDG4/Geant4StackingAction.h" #include "DDG4/Geant4GeneratorAction.h" +#include "DDG4/Geant4UserInitialization.h" +#include "DDG4/Geant4DetectorConstruction.h" #include "DDG4/Geant4PhysicsList.h" #include "DDG4/Geant4UIManager.h" #include "DDG4/Geant4Kernel.h" #include "DDG4/Geant4Random.h" // Geant4 include files -#include <G4Version.hh> +#include "G4Version.hh" #include "G4UserRunAction.hh" #include "G4UserEventAction.hh" #include "G4UserTrackingAction.hh" @@ -38,31 +40,29 @@ #include "G4VUserPhysicsList.hh" #include "G4VModularPhysicsList.hh" #include "G4VUserPrimaryGeneratorAction.hh" +#include "G4VUserActionInitialization.hh" +#include "G4VUserDetectorConstruction.hh" // C/C++ include files #include <memory> #include <stdexcept> +namespace { + G4Mutex action_mutex=G4MUTEX_INITIALIZER; +} + /// Namespace for the AIDA detector description toolkit namespace DD4hep { /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit namespace Simulation { - namespace { - Geant4Context* s_globalContext = 0; - } - - Geant4Context* ddg4_globalContext() { - return s_globalContext; - } - /// Sequence handler implementing common actions to all sequences. template <typename T> class SequenceHdl { public: typedef SequenceHdl<T> Base; T* m_sequence; - Geant4Context* m_activeContext; + mutable Geant4Context* m_activeContext; /// Default constructor SequenceHdl() : m_sequence(0), m_activeContext(0) { @@ -78,6 +78,12 @@ namespace DD4hep { m_sequence = s; if ( m_sequence ) m_sequence->addRef(); } + void updateContext(Geant4Context* ctxt) { + m_activeContext = ctxt; + if ( m_sequence ) { + m_sequence->updateContext(ctxt); + } + } void _release() { releasePtr(m_sequence); InstanceCount::decrement(this); @@ -88,21 +94,17 @@ namespace DD4hep { Geant4Kernel& kernel() const { return context()->kernel(); } - - void setContextToClients() { - if ( m_sequence ) (Geant4Action::ContextUpdate(m_activeContext))(m_sequence); - } - void releaseContextFromClients() { - if ( m_sequence ) Geant4Action::ContextUpdate(0)(m_sequence); + void configureFiber(Geant4Context* ctxt) { + if ( m_sequence ) { + m_sequence->configureFiber(ctxt); + } } void createClientContext(const G4Run* run) { Geant4Run* r = new Geant4Run(run); m_activeContext->setRun(r); - setContextToClients(); } void destroyClientContext(const G4Run*) { Geant4Run* r = m_activeContext->runPtr(); - releaseContextFromClients(); if ( r ) { m_activeContext->setRun(0); deletePtr(r); @@ -111,11 +113,9 @@ namespace DD4hep { void createClientContext(const G4Event* evt) { Geant4Event* e = new Geant4Event(evt,Geant4Random::instance()); m_activeContext->setEvent(e); - setContextToClients(); } void destroyClientContext(const G4Event*) { Geant4Event* e = m_activeContext->eventPtr(); - releaseContextFromClients(); if ( e ) { m_activeContext->setEvent(0); deletePtr(e); @@ -132,12 +132,17 @@ namespace DD4hep { * @author M.Frank * @version 1.0 */ - class Geant4UserRunAction : public G4UserRunAction, public SequenceHdl<Geant4RunActionSequence> { + class Geant4UserRunAction : + public G4UserRunAction, + public SequenceHdl<Geant4RunActionSequence> + { public: Geant4UserEventAction* eventAction; /// Standard constructor Geant4UserRunAction(Geant4Context* ctxt, Geant4RunActionSequence* seq) : Base(ctxt, seq), eventAction(0) { + updateContext(ctxt); + configureFiber(ctxt); } /// Default destructor virtual ~Geant4UserRunAction() { @@ -154,12 +159,17 @@ namespace DD4hep { * @author M.Frank * @version 1.0 */ - class Geant4UserEventAction : public G4UserEventAction, public SequenceHdl<Geant4EventActionSequence> { + class Geant4UserEventAction : + public G4UserEventAction, + public SequenceHdl<Geant4EventActionSequence> + { public: Geant4UserRunAction* runAction; /// Standard constructor Geant4UserEventAction(Geant4Context* ctxt, Geant4EventActionSequence* seq) : Base(ctxt, seq), runAction(0) { + updateContext(ctxt); + configureFiber(ctxt); } /// Default destructor virtual ~Geant4UserEventAction() { @@ -176,18 +186,22 @@ namespace DD4hep { * @author M.Frank * @version 1.0 */ - class Geant4UserTrackingAction : public G4UserTrackingAction, public SequenceHdl<Geant4TrackingActionSequence> { + class Geant4UserTrackingAction : + public G4UserTrackingAction, + public SequenceHdl<Geant4TrackingActionSequence> + { public: /// Standard constructor Geant4UserTrackingAction(Geant4Context* ctxt, Geant4TrackingActionSequence* seq) : Base(ctxt, seq) { + updateContext(ctxt); + configureFiber(ctxt); } /// Default destructor virtual ~Geant4UserTrackingAction() { } /// Pre-track action callback virtual void PreUserTrackingAction(const G4Track* trk) { - setContextToClients(); m_sequence->context()->kernel().setTrackMgr(fpTrackingManager); m_sequence->begin(trk); } @@ -195,7 +209,6 @@ namespace DD4hep { virtual void PostUserTrackingAction(const G4Track* trk) { m_sequence->end(trk); m_sequence->context()->kernel().setTrackMgr(0); - releaseContextFromClients(); //Let's leave this out for now...Frank has dirty tricks. } }; @@ -205,50 +218,53 @@ namespace DD4hep { * @author M.Frank * @version 1.0 */ - class Geant4UserStackingAction : public G4UserStackingAction, public SequenceHdl<Geant4StackingActionSequence> { + class Geant4UserStackingAction : + public G4UserStackingAction, + public SequenceHdl<Geant4StackingActionSequence> + { public: /// Standard constructor Geant4UserStackingAction(Geant4Context* ctxt, Geant4StackingActionSequence* seq) : Base(ctxt, seq) { + updateContext(ctxt); + configureFiber(ctxt); } /// Default destructor virtual ~Geant4UserStackingAction() { } /// New-stage callback virtual void NewStage() { - setContextToClients(); m_sequence->newStage(); - releaseContextFromClients(); //Let's leave this out for now...Frank has dirty tricks. } /// Preparation callback virtual void PrepareNewEvent() { - setContextToClients(); m_sequence->prepare(); - releaseContextFromClients(); //Let's leave this out for now...Frank has dirty tricks. } }; + /// Concrete implementation of the Geant4 generator action /** @class Geant4UserGeneratorAction * * @author M.Frank * @version 1.0 */ - class Geant4UserGeneratorAction : public G4VUserPrimaryGeneratorAction, public SequenceHdl<Geant4GeneratorActionSequence> { + class Geant4UserGeneratorAction : + public G4VUserPrimaryGeneratorAction, + public SequenceHdl<Geant4GeneratorActionSequence> + { public: /// Standard constructor Geant4UserGeneratorAction(Geant4Context* ctxt, Geant4GeneratorActionSequence* seq) : G4VUserPrimaryGeneratorAction(), Base(ctxt, seq) { + updateContext(ctxt); + configureFiber(ctxt); } /// Default destructor virtual ~Geant4UserGeneratorAction() { } /// Generate primary particles - virtual void GeneratePrimaries(G4Event* event) { - createClientContext(event); - (*m_sequence)(event); - releaseContextFromClients(); //Let's leave this out for now...Frank has dirty tricks. - } + virtual void GeneratePrimaries(G4Event* event); }; /// Concrete implementation of the Geant4 stepping action @@ -257,54 +273,214 @@ namespace DD4hep { * @author M.Frank * @version 1.0 */ - class Geant4UserSteppingAction : public G4UserSteppingAction, public SequenceHdl<Geant4SteppingActionSequence> { + class Geant4UserSteppingAction : + public G4UserSteppingAction, + public SequenceHdl<Geant4SteppingActionSequence> + { public: /// Standard constructor Geant4UserSteppingAction(Geant4Context* ctxt, Geant4SteppingActionSequence* seq) : Base(ctxt, seq) { + updateContext(ctxt); + configureFiber(ctxt); } /// Default destructor virtual ~Geant4UserSteppingAction() { } /// User stepping callback virtual void UserSteppingAction(const G4Step* s) { - setContextToClients(); (*m_sequence)(s, fpSteppingManager); - releaseContextFromClients(); //Let's leave this out for now...Frank has dirty tricks. } }; + /// Concrete implementation of the Geant4 user detector construction action sequence + /** @class Geant4UserDetectorConstruction + * + * @author M.Frank + * @version 1.0 + */ + class Geant4UserDetectorConstruction : + public G4VUserDetectorConstruction, + public SequenceHdl<Geant4DetectorConstructionSequence> + { + protected: + Geant4DetectorConstructionContext m_ctxt; + public: + /// Standard constructor + Geant4UserDetectorConstruction(Geant4Context* ctxt, Geant4DetectorConstructionSequence* seq) + : G4VUserDetectorConstruction(), Base(ctxt, seq), + m_ctxt(ctxt->kernel().lcdd(), this) + { + } + /// Default destructor + virtual ~Geant4UserDetectorConstruction() { + } + /// Call the actions for the construction of the sensitive detectors and the field + virtual void ConstructSDandField(); + /// Call the actions to construct the detector geometry + virtual G4VPhysicalVolume* Construct(); + }; + + /// Concrete implementation of the Geant4 user initialization action sequence + /** @class Geant4UserActionInitialization + * + * @author M.Frank + * @version 1.0 + */ + class Geant4UserActionInitialization : + public G4VUserActionInitialization, + public SequenceHdl<Geant4UserInitializationSequence> + { + public: + /// Standard constructor + Geant4UserActionInitialization(Geant4Context* ctxt, Geant4UserInitializationSequence* seq) + : G4VUserActionInitialization(), Base(ctxt, seq) { + } + /// Default destructor + virtual ~Geant4UserActionInitialization() { + } + /// Build the actions for the worker thread + virtual void Build() const; + /// Build the action sequences for the master thread + virtual void BuildForMaster() const; + }; + /// Begin-of-run callback void Geant4UserRunAction::BeginOfRunAction(const G4Run* run) { createClientContext(run); kernel().executePhase("begin-run",(const void**)&run); - eventAction->setContextToClients(); - m_sequence->begin(run); + if ( m_sequence ) m_sequence->begin(run); // Action not mandatory } /// End-of-run callback void Geant4UserRunAction::EndOfRunAction(const G4Run* run) { - m_sequence->end(run); + if ( m_sequence ) m_sequence->end(run); // Action not mandatory kernel().executePhase("end-run",(const void**)&run); - eventAction->releaseContextFromClients(); destroyClientContext(run); } /// Begin-of-event callback void Geant4UserEventAction::BeginOfEventAction(const G4Event* evt) { - runAction->setContextToClients(); - setContextToClients(); kernel().executePhase("begin-event",(const void**)&evt); - m_sequence->begin(evt); + if ( m_sequence ) m_sequence->begin(evt); // Action not mandatory } /// End-of-event callback void Geant4UserEventAction::EndOfEventAction(const G4Event* evt) { - m_sequence->end(evt); - runAction->releaseContextFromClients(); + if ( m_sequence ) m_sequence->end(evt); // Action not mandatory kernel().executePhase("end-event",(const void**)&evt); destroyClientContext(evt); } + + /// Generate primary particles + void Geant4UserGeneratorAction::GeneratePrimaries(G4Event* event) { + createClientContext(event); + if ( m_sequence ) { + (*m_sequence)(event); + return; + } + throw std::runtime_error("GeneratePrimaries: Panic! No action sequencer defined. " + "No primary particles can be produced."); + } + + /// Instantiate Geant4 sensitive detectors and electro-magnetic field + void Geant4UserDetectorConstruction::ConstructSDandField() { + G4AutoLock protection_lock(&action_mutex); + Geant4Context* ctx = m_sequence->context(); + Geant4Kernel* krnl = 0; + try { + krnl = &kernel().worker(::pthread_self()); + } + catch(...) { + } + if ( 0 == krnl ) { + krnl = &kernel().createWorker(); + } + updateContext(krnl->workerContext()); + m_sequence->constructField(&m_ctxt); + m_sequence->constructSensitives(&m_ctxt); + updateContext(ctx); + } + + /// Construct electro magnetic field entity from the DD4hep field + G4VPhysicalVolume* Geant4UserDetectorConstruction::Construct() { + // The G4TransportationManager is thread-local. + // Thus, regardless of whether the field class object is global or local + // to a certain volume, a field object must be assigned to G4FieldManager. + G4AutoLock protection_lock(&action_mutex); + updateContext(m_sequence->context()); + m_sequence->constructGeo(&m_ctxt); + if ( 0 == m_ctxt.world ) { + m_sequence->except("+++ Executing G4 detector construction did not result in a valid world volume!"); + } + return m_ctxt.world; + } + + /// Build the actions for the worker thread + void Geant4UserActionInitialization::Build() const { + G4AutoLock protection_lock(&action_mutex); + Geant4Kernel* krnl = 0; + try { + krnl = &kernel().worker(::pthread_self()); + } + catch(...) { + } + if ( 0 == krnl ) { + krnl = &kernel().createWorker(); + } + Geant4Context* ctx = krnl->workerContext(); + + if ( m_sequence ) { + Geant4Context* old = m_sequence->context(); + m_sequence->info("+++ Executing Geant4UserActionInitialization::Build. " + "Context:%p Kernel:%p [%ld]", (void*)ctx, (void*)krnl, krnl->id()); + + m_sequence->updateContext(ctx); + m_sequence->build(); + m_sequence->updateContext(old); + } + // Set user generator action sequence. Not optional, since event context is defined inside + Geant4UserGeneratorAction* gen_action = new Geant4UserGeneratorAction(ctx,krnl->generatorAction(false)); + SetUserAction(gen_action); + + // Set the run action sequence. Not optional, since run context is defined/destroyed inside + Geant4UserRunAction* run_action = new Geant4UserRunAction(ctx,krnl->runAction(false)); + SetUserAction(run_action); + + // Set the event action sequence. Not optional, since event context is destroyed inside + Geant4UserEventAction* evt_action = new Geant4UserEventAction(ctx,krnl->eventAction(false)); + run_action->eventAction = evt_action; + evt_action->runAction = run_action; + SetUserAction(evt_action); + + // Set the tracking action sequence + Geant4TrackingActionSequence* trk_action = krnl->trackingAction(false); + if ( trk_action ) { + Geant4UserTrackingAction* action = new Geant4UserTrackingAction(ctx, trk_action); + SetUserAction(action); + } + // Set the stepping action sequence + Geant4SteppingActionSequence* stp_action = krnl->steppingAction(false); + if ( stp_action ) { + Geant4UserSteppingAction* action = new Geant4UserSteppingAction(ctx, stp_action); + SetUserAction(action); + } + // Set the stacking action sequence + Geant4StackingActionSequence* stk_action = krnl->stackingAction(false); + if ( stk_action ) { + Geant4UserStackingAction* action = new Geant4UserStackingAction(ctx, stk_action); + SetUserAction(action); + } + + } + + /// Build the action sequences for the master thread + void Geant4UserActionInitialization::BuildForMaster() const { + if ( m_sequence ) { + m_sequence->info("+++ Executing Geant4UserActionInitialization::BuildForMaster...."); + m_sequence->buildMaster(); + } + } } } @@ -322,11 +498,40 @@ using namespace DD4hep::Simulation; #include "G4RunManager.hh" #include "G4PhysListFactory.hh" +class Geant4Compatibility { +public: + Geant4Compatibility() {} + Geant4DetectorConstructionSequence* buildDefaultDetectorConstruction(Geant4Kernel& kernel); +}; +Geant4DetectorConstructionSequence* Geant4Compatibility::buildDefaultDetectorConstruction(Geant4Kernel& kernel) { + Geant4Action* cr; + Geant4DetectorConstruction* det_cr; + Geant4Context* ctx = kernel.workerContext(); + Geant4DetectorConstructionSequence* seq = kernel.detectorConstruction(true); + printout(WARNING, "Geant4Exec", "+++ Building default Geant4DetectorConstruction for single threaded compatibility."); + + // Attach first the geometry converter from DD4hep to Geant4 + cr = PluginService::Create<Geant4Action*>("Geant4DetectorGeometryConstruction",ctx,string("ConstructGeometry")); + det_cr = dynamic_cast<Geant4DetectorConstruction*>(cr); + if ( det_cr ) + seq->adopt(det_cr); + else + throw runtime_error("Panic! Failed to build Geant4DetectorGeometryConstruction."); + // Attach the sensitive detector manipulator: + cr = PluginService::Create<Geant4Action*>("Geant4DetectorSensitivesConstruction",ctx,string("ConstructSensitives")); + det_cr = dynamic_cast<Geant4DetectorConstruction*>(cr); + if ( det_cr ) + seq->adopt(det_cr); + else + throw runtime_error("Panic! Failed to build Geant4DetectorSensitivesConstruction."); + return seq; +} + /// Configure the simulation int Geant4Exec::configure(Geant4Kernel& kernel) { CLHEP::HepRandom::setTheEngine(new CLHEP::RanecuEngine); Geometry::LCDD& lcdd = kernel.lcdd(); - Geant4Context* ctx = s_globalContext = new Geant4Context(&kernel); + Geant4Context* ctx = kernel.workerContext(); Geant4Random* rndm = Geant4Random::instance(false); if ( !rndm ) { @@ -334,7 +539,6 @@ int Geant4Exec::configure(Geant4Kernel& kernel) { /// Initialize the engine etc. rndm->initialize(); } - kernel.executePhase("configure",0); // Construct the default run manager @@ -343,52 +547,45 @@ int Geant4Exec::configure(Geant4Kernel& kernel) { // Check if the geometry was loaded if (lcdd.sensitiveDetectors().size() <= 1) { printout(WARNING, "Geant4Exec", "+++ Only %d subdetectors present. " - "You sure you loaded the geometry properly?",int(lcdd.sensitiveDetectors().size())); + "You sure you loaded the geometry properly?", + int(lcdd.sensitiveDetectors().size())); } - // Get the detector constructed - Geant4DetectorConstruction* detector = Geant4DetectorConstruction::instance(kernel); - runManager.SetUserInitialization(detector); - Geant4PhysicsListActionSequence* seq = kernel.physicsList(false); - if ( 0 == seq ) { - seq = kernel.physicsList(true); - seq->property("Extends").set<string>("QGSP_BERT"); + // Get the detector constructed + Geant4DetectorConstructionSequence* user_det = kernel.detectorConstruction(false); + if ( 0 == user_det && kernel.isMultiThreaded() ) { + throw runtime_error("Panic! No valid detector construction sequencer present. [Mandatory MT]"); + } + if ( 0 == user_det && !kernel.isMultiThreaded() ) { + user_det = Geant4Compatibility().buildDefaultDetectorConstruction(kernel); } - G4VUserPhysicsList* physics = seq->extensionList(); + Geant4UserDetectorConstruction* det_seq = new Geant4UserDetectorConstruction(ctx,user_det); + runManager.SetUserInitialization(det_seq); + + // Get the physics list constructed + Geant4PhysicsListActionSequence* phys_seq = kernel.physicsList(false); + if ( 0 == phys_seq ) { + string phys_model = "QGSP_BERT"; + phys_seq = kernel.physicsList(true); + phys_seq->property("extends").set<string>(phys_model); + } + G4VUserPhysicsList* physics = phys_seq->extensionList(); if (0 == physics) { throw runtime_error("Panic! No valid user physics list present!"); } runManager.SetUserInitialization(physics); - // Set user generator action sequence. Not optional, since event context is defined inside - Geant4UserGeneratorAction* gen_action = - new Geant4UserGeneratorAction(ctx,kernel.generatorAction(false)); - runManager.SetUserAction(gen_action); - - // Set the run action sequence. Not optional, since run context is defined/destroyed inside - Geant4UserRunAction* run_action = new Geant4UserRunAction(ctx,kernel.runAction(false)); - runManager.SetUserAction(run_action); - - // Set the event action sequence. Not optional, since event context is destroyed inside - Geant4UserEventAction* evt_action = new Geant4UserEventAction(ctx,kernel.eventAction(false)); - runManager.SetUserAction(evt_action); - run_action->eventAction = evt_action; - evt_action->runAction = run_action; - - // Set the tracking action sequence - if (kernel.trackingAction(false)) { - Geant4UserTrackingAction* action = new Geant4UserTrackingAction(ctx,kernel.trackingAction(false)); - runManager.SetUserAction(action); - } - // Set the stepping action sequence - if (kernel.steppingAction(false)) { - Geant4UserSteppingAction* action = new Geant4UserSteppingAction(ctx,kernel.steppingAction(false)); - runManager.SetUserAction(action); + + // Construct the remaining user initialization in multi-threaded mode + Geant4UserInitializationSequence* user_init = kernel.userInitialization(false); + if ( 0 == user_init && kernel.isMultiThreaded() ) { + throw runtime_error("Panic! No valid user initialization sequencer present. [Mandatory MT]"); } - // Set the stacking action sequence - if (kernel.stackingAction(false)) { - Geant4UserStackingAction* action = new Geant4UserStackingAction(ctx,kernel.stackingAction(false)); - runManager.SetUserAction(action); + else if ( 0 == user_init && !kernel.isMultiThreaded() ) { + // Use default actions registered to the default kernel. Will do the right thing... + user_init = kernel.userInitialization(true); } + Geant4UserActionInitialization* init = new Geant4UserActionInitialization(ctx,user_init); + runManager.SetUserInitialization(init); return 1; } @@ -432,6 +629,5 @@ int Geant4Exec::run(Geant4Kernel& kernel) { /// Run the simulation int Geant4Exec::terminate(Geant4Kernel& kernel) { kernel.executePhase("terminate",0); - deletePtr(s_globalContext); return 1; } diff --git a/DDG4/src/Geant4GeneratorAction.cpp b/DDG4/src/Geant4GeneratorAction.cpp index f6a1d6feaca7eb12807b16e7055034daf9afce5a..c54dbb16d87394067227bbdaff2f6f4118505c04 100644 --- a/DDG4/src/Geant4GeneratorAction.cpp +++ b/DDG4/src/Geant4GeneratorAction.cpp @@ -15,14 +15,21 @@ // Framework include files #include "DD4hep/InstanceCount.h" #include "DDG4/Geant4GeneratorAction.h" - +// Geant4 headers +#include "G4Threading.hh" +#include "G4AutoLock.hh" // C/C++ include files #include <stdexcept> +using namespace std; using namespace DD4hep::Simulation; +namespace { + G4Mutex action_mutex=G4MUTEX_INITIALIZER; +} + /// Standard constructor -Geant4GeneratorAction::Geant4GeneratorAction(Geant4Context* ctxt, const std::string& nam) +Geant4GeneratorAction::Geant4GeneratorAction(Geant4Context* ctxt, const string& nam) : Geant4Action(ctxt, nam) { InstanceCount::increment(this); } @@ -33,7 +40,45 @@ Geant4GeneratorAction::~Geant4GeneratorAction() { } /// Standard constructor -Geant4GeneratorActionSequence::Geant4GeneratorActionSequence(Geant4Context* ctxt, const std::string& nam) +Geant4SharedGeneratorAction::Geant4SharedGeneratorAction(Geant4Context* ctxt, const string& nam) + : Geant4GeneratorAction(ctxt, nam) +{ + InstanceCount::increment(this); +} + +/// Default destructor +Geant4SharedGeneratorAction::~Geant4SharedGeneratorAction() { + releasePtr(m_action); + InstanceCount::decrement(this); +} + +/// Set or update client for the use in a new thread fiber +void Geant4SharedGeneratorAction::configureFiber(Geant4Context* thread_context) { + m_action->configureFiber(thread_context); +} + +/// Underlying object to be used during the execution of this thread +void Geant4SharedGeneratorAction::use(Geant4GeneratorAction* action) { + if (action) { + action->addRef(); + m_action = action; + return; + } + throw runtime_error("Geant4SharedGeneratorAction: Attempt to use invalid actor!"); +} + +/// User generator callback +void Geant4SharedGeneratorAction::operator()(G4Event* event) { + if ( m_action ) { + G4AutoLock protection_lock(&action_mutex); { + ContextSwap swap(m_action,context()); + (*m_action)(event); + } + } +} + +/// Standard constructor +Geant4GeneratorActionSequence::Geant4GeneratorActionSequence(Geant4Context* ctxt, const string& nam) : Geant4Action(ctxt, nam) { m_needsControl = true; InstanceCount::increment(this); @@ -47,20 +92,35 @@ Geant4GeneratorActionSequence::~Geant4GeneratorActionSequence() { InstanceCount::decrement(this); } +/// Set or update client context +void Geant4GeneratorActionSequence::updateContext(Geant4Context* ctxt) { + m_context = ctxt; + m_actors.updateContext(ctxt); +} + +/// Set or update client for the use in a new thread fiber +void Geant4GeneratorActionSequence::configureFiber(Geant4Context* thread_context) { + m_actors(&Geant4Action::configureFiber, thread_context); +} + +/// Get an action by name +Geant4GeneratorAction* Geant4GeneratorActionSequence::get(const string& nam) const { + return m_actors.get(FindByName(TypeName::split(nam).second)); +} + /// Add an actor responding to all callbacks. Sequence takes ownership. void Geant4GeneratorActionSequence::adopt(Geant4GeneratorAction* action) { if (action) { + G4AutoLock protection_lock(&action_mutex); action->addRef(); m_actors.add(action); return; } - throw std::runtime_error("Geant4GeneratorActionSequence: Attempt to add invalid actor!"); + throw runtime_error("Geant4GeneratorActionSequence: Attempt to add invalid actor!"); } /// Generator callback void Geant4GeneratorActionSequence::operator()(G4Event* event) { - m_actors(ContextUpdate(context())); m_actors(&Geant4GeneratorAction::operator(), event); m_calls(event); - m_actors(ContextUpdate(0)); } diff --git a/DDG4/src/Geant4Handle.cpp b/DDG4/src/Geant4Handle.cpp index 38e9091a5938b10f0ad1974e87a988b67f4f67e2..956b94acc934a53adc0b75659fd14260e6f13de2 100644 --- a/DDG4/src/Geant4Handle.cpp +++ b/DDG4/src/Geant4Handle.cpp @@ -28,6 +28,12 @@ #include "DDG4/Geant4SensDetAction.h" #include "DDG4/Geant4PhysicsList.h" #include "DDG4/Geant4ActionPhase.h" +#include "DDG4/Geant4UserInitialization.h" +#include "DDG4/Geant4DetectorConstruction.h" + +// Geant4 include files +#include "G4Threading.hh" +#include "G4AutoLock.hh" // C/C++ include files #include <stdexcept> @@ -35,181 +41,248 @@ using namespace std; using namespace DD4hep; using namespace DD4hep::Simulation; +namespace { + G4Mutex creation_mutex=G4MUTEX_INITIALIZER; +} namespace DD4hep { namespace Simulation { -template <typename TYPE> static inline TYPE* checked_value(TYPE* p) { - if (p) { - return p; - } - throw runtime_error( - format("Geant4Handle", "Attempt to access an invalid object of type:%s!", typeName(typeid(TYPE)).c_str())); -} + template <typename TYPE> static inline TYPE* checked_value(TYPE* p) { + if (p) { + return p; + } + throw runtime_error(format("Geant4Handle", "Attempt to access an invalid object of type:%s!", typeName(typeid(TYPE)).c_str())); + } -template <typename TYPE> Geant4Handle<TYPE>::Geant4Handle() - : value(0) { -} + template <typename TYPE> Geant4Handle<TYPE>::Geant4Handle() + : value(0) { + } -template <typename TYPE> Geant4Handle<TYPE>::Geant4Handle(TYPE* typ) -: value(typ) { - if (value) - value->addRef(); -} + template <typename TYPE> Geant4Handle<TYPE>::Geant4Handle(TYPE* typ) + : value(typ) { + if (value) + value->addRef(); + } -template <typename TYPE> Geant4Handle<TYPE>::Geant4Handle(const Geant4Handle<TYPE>& handle) - : value(0) { - value = handle.get(); - if (value) - value->addRef(); -} + template <typename TYPE> Geant4Handle<TYPE>::Geant4Handle(const Geant4Handle<TYPE>& handle) + : value(0) { + value = handle.get(); + if (value) + value->addRef(); + } -template <typename TYPE> Geant4Handle<TYPE>::Geant4Handle(Geant4Kernel& kernel, const string& type_name) - : value(0) { - TypeName typ = TypeName::split(type_name); - Geant4Context ctxt(&kernel); - Geant4Action* object = PluginService::Create<Geant4Action*>(typ.first, &ctxt, typ.second); - if (!object && typ.first == typ.second) { - typ.first = typeName(typeid(TYPE)); - printout(DEBUG, "Geant4Handle<Geant4Sensitive>", "Object factory for %s not found. Try out %s", typ.second.c_str(), - typ.first.c_str()); - object = PluginService::Create<Geant4Action*>(typ.first, &ctxt, typ.second); - if (!object) { - size_t idx = typ.first.rfind(':'); - if (idx != string::npos) - typ.first = string(typ.first.substr(idx + 1)); - printout(DEBUG, "Geant4Handle<Geant4Sensitive>", "Try out object factory for %s", typ.first.c_str()); - object = PluginService::Create<Geant4Action*>(typ.first, &ctxt, typ.second); + template <typename TYPE> TYPE* _create_object(Geant4Kernel& kernel, const TypeName& typ) { + Geant4Context* ctxt = kernel.workerContext(); + Geant4Action* object = PluginService::Create<Geant4Action*>(typ.first, ctxt, typ.second); + if (!object && typ.first == typ.second) { + string _t = typeName(typeid(TYPE)); + printout(DEBUG, "Geant4Handle", "Object factory for %s not found. Try out %s", + typ.second.c_str(), _t.c_str()); + object = PluginService::Create<Geant4Action*>(_t, ctxt, typ.second); + if (!object) { + size_t idx = _t.rfind(':'); + if (idx != string::npos) + _t = string(_t.substr(idx + 1)); + printout(DEBUG, "Geant4Handle", "Try out object factory for %s",_t.c_str()); + object = PluginService::Create<Geant4Action*>(_t, ctxt, typ.second); + } + } + if (object) { + TYPE* ptr = dynamic_cast<TYPE*>(object); + if (ptr) { + return ptr; + } + throw runtime_error(format("Geant4Handle", "Failed to convert object of type %s to handle of type %s!", + typ.first.c_str(),typ.second.c_str())); + } + throw runtime_error(format("Geant4Handle", "Failed to create object of type %s!", typ.first.c_str())); } - } - if (object) { - TYPE* ptr = dynamic_cast<TYPE*>(object); - if (ptr) { - value = ptr; - return; - } - throw runtime_error( - format("Geant4Handle", "Failed to convert object of type %s to handle of type %s!", type_name.c_str(), - typeName(typeid(TYPE)).c_str())); - } - throw runtime_error(format("Geant4Handle", "Failed to create object of type %s!", type_name.c_str())); -} -template <typename TYPE> Geant4Handle<TYPE>::Geant4Handle(Geant4Kernel& kernel, const char* type_name_char) - : value(0) { - string type_name = type_name_char; - TypeName typ = TypeName::split(type_name); - Geant4Context ctxt(&kernel); - Geant4Action* object = PluginService::Create<Geant4Action*>(typ.first, &ctxt, typ.second); - if (!object && typ.first == typ.second) { - typ.first = typeName(typeid(TYPE)); - printout(DEBUG, "Geant4Handle<Geant4Sensitive>", "Object factory for %s not found. Try out %s", typ.second.c_str(), - typ.first.c_str()); - object = PluginService::Create<Geant4Action*>(typ.first, &ctxt, typ.second); - if (!object) { - size_t idx = typ.first.rfind(':'); - if (idx != string::npos) - typ.first = string(typ.first.substr(idx + 1)); - printout(DEBUG, "Geant4Handle<Geant4Sensitive>", "Try out object factory for %s", typ.first.c_str()); - object = PluginService::Create<Geant4Action*>(typ.first, &ctxt, typ.second); + template <typename TYPE, typename CONT> + TYPE* _create_share(Geant4Kernel& kernel, + CONT& (Geant4Kernel::*pmf)(), + const string& type_name, + const string& shared_typ, + bool shared, TYPE*) + { + TypeName typ = TypeName::split(type_name); + Geant4Kernel& k = shared ? kernel.master() : kernel; + if ( shared && k.isMultiThreaded() ) { + typedef typename TYPE::shared_type _ST; + TypeName s_type = TypeName::split(shared_typ+"/"+typ.second); + _ST* object = (_ST*)_create_object<TYPE>(kernel,s_type); + CONT& container = (k.*pmf)(); + TYPE* value = 0; + // Need to protect the global action sequence! + G4AutoLock protection_lock(&creation_mutex); { + value = container.get(typ.second); + if ( !value ) value = _create_object<TYPE>(k,typ); + container.adopt(value); + } + object->use(value); + value->info("+++ Created shared object for %s of type %s.", + typ.second.c_str(),typeName(typeid(TYPE)).c_str()); + return object; + } + TYPE* value = _create_object<TYPE>(k,typ); + return value; } - } - if (object) { - TYPE* ptr = dynamic_cast<TYPE*>(object); - if (ptr) { - value = ptr; - return; - } - throw runtime_error( - format("Geant4Handle", "Failed to convert object of type %s to handle of type %s!", type_name.c_str(), - typeName(typeid(TYPE)).c_str())); - } - throw runtime_error(format("Geant4Handle", "Failed to create object of type %s!", type_name.c_str())); -} -template <typename TYPE> Geant4Handle<TYPE>::~Geant4Handle() { - if (value) - value->release(); - value = 0; -} + template <typename TYPE> + Geant4Handle<TYPE>::Geant4Handle(Geant4Kernel& kernel, const string& type_name, bool /* shared */) { + value = _create_object<TYPE>(kernel,TypeName::split(type_name)); + } -template <typename TYPE> TYPE* Geant4Handle<TYPE>::release() { - TYPE* temp = value; - value = 0; - return temp; -} + template <typename TYPE> + Geant4Handle<TYPE>::Geant4Handle(Geant4Kernel& kernel, const char* type_name_char, bool /* shared */) { + value = _create_object<TYPE>(kernel,TypeName::split(type_name_char ? type_name_char : "????")); + } -template <typename TYPE> void Geant4Handle<TYPE>::checked_assign(TYPE* p) { - if (value) - value->release(); - value = checked_value(p); - if (value) - value->addRef(); -} + template <typename TYPE> Geant4Handle<TYPE>::~Geant4Handle() { + if (value) + value->release(); + value = 0; + } -template <typename TYPE> Property& Geant4Handle<TYPE>::operator[](const string& property_name) const { - PropertyManager& pm = checked_value(value)->properties(); - return pm[property_name]; -} + template <typename TYPE> TYPE* Geant4Handle<TYPE>::release() { + TYPE* temp = value; + value = 0; + return temp; + } -template <typename TYPE> Geant4Handle<TYPE>::operator TYPE*() const { - return checked_value(value); -} + template <typename TYPE> void Geant4Handle<TYPE>::checked_assign(TYPE* p) { + if (value) + value->release(); + value = checked_value(p); + if (value) + value->addRef(); + } -template <typename TYPE> bool Geant4Handle<TYPE>::operator!() const { - return 0 == value; -} + template <typename TYPE> Property& Geant4Handle<TYPE>::operator[](const string& property_name) const { + PropertyManager& pm = checked_value(value)->properties(); + return pm[property_name]; + } -template <typename TYPE> TYPE* Geant4Handle<TYPE>::get() const { - return checked_value(value); -} + template <typename TYPE> Geant4Handle<TYPE>::operator TYPE*() const { + return checked_value(value); + } -template <typename TYPE> TYPE* Geant4Handle<TYPE>::operator->() const { - return checked_value(value); -} + template <typename TYPE> bool Geant4Handle<TYPE>::operator!() const { + return 0 == value; + } -template <typename TYPE> Geant4Action* Geant4Handle<TYPE>::action() const { - return checked_value(value); -} + template <typename TYPE> TYPE* Geant4Handle<TYPE>::get() const { + return checked_value(value); + } -template <typename TYPE> Geant4Handle<TYPE>& Geant4Handle<TYPE>::operator=(const Geant4Handle& handle) { - if ( &handle != this ) { - if (value) value->release(); - value = handle.get(); - if (value) value->addRef(); - } - return *this; -} + template <typename TYPE> TYPE* Geant4Handle<TYPE>::operator->() const { + return checked_value(value); + } -template <typename TYPE> Geant4Handle<TYPE>& Geant4Handle<TYPE>::operator=(TYPE* typ) { - if ( typ != value ) { - if (value) value->release(); - value = typ; - if (value) value->addRef(); - } - return *this; -} + template <typename TYPE> Geant4Action* Geant4Handle<TYPE>::action() const { + return checked_value(value); + } -//namespace DD4hep { -// namespace Simulation { + template <typename TYPE> Geant4Handle<TYPE>& Geant4Handle<TYPE>::operator=(const Geant4Handle& handle) { + if ( &handle != this ) { + if (value) value->release(); + value = handle.get(); + if (value) value->addRef(); + } + return *this; + } + + template <typename TYPE> Geant4Handle<TYPE>& Geant4Handle<TYPE>::operator=(TYPE* typ) { + if ( typ != value ) { + if (value) value->release(); + value = typ; + if (value) value->addRef(); + } + return *this; + } + + //namespace DD4hep { + // namespace Simulation { KernelHandle::KernelHandle() { value = &Geant4Kernel::instance(Geometry::LCDD::getInstance()); } + KernelHandle::KernelHandle(Geant4Kernel* k) : value(k) { + } + KernelHandle KernelHandle::worker() { + Geant4Kernel* k = value ? &value->worker(::pthread_self()) : 0; + if ( k ) return KernelHandle(k); + throw runtime_error(format("KernelHandle", "Cannot access worker context [Invalid Handle]")); + } void KernelHandle::destroy() { if ( value ) delete value; value = 0; } + template <> + Geant4Handle<Geant4RunAction>::Geant4Handle(Geant4Kernel& kernel, const string& type_name, bool shared) { + value = _create_share(kernel,&Geant4Kernel::runAction,type_name,"Geant4SharedRunAction",shared,(handled_type*)0); + } + template <> + Geant4Handle<Geant4RunAction>::Geant4Handle(Geant4Kernel& kernel, const char* type_name, bool shared) { + value = _create_share(kernel,&Geant4Kernel::runAction,type_name,"Geant4SharedRunAction",shared,(handled_type*)0); + } + + template <> + Geant4Handle<Geant4EventAction>::Geant4Handle(Geant4Kernel& kernel, const string& type_name, bool shared) { + value = _create_share(kernel,&Geant4Kernel::eventAction,type_name,"Geant4SharedEventAction",shared,(handled_type*)0); + } + template <> + Geant4Handle<Geant4EventAction>::Geant4Handle(Geant4Kernel& kernel, const char* type_name, bool shared) { + value = _create_share(kernel,&Geant4Kernel::eventAction,type_name,"Geant4SharedEventAction",shared,(handled_type*)0); + } + + template <> + Geant4Handle<Geant4GeneratorAction>::Geant4Handle(Geant4Kernel& kernel, const string& type_name, bool shared) { + value = _create_share(kernel,&Geant4Kernel::generatorAction,type_name,"Geant4SharedGeneratorAction",shared,(handled_type*)0); + } + template <> + Geant4Handle<Geant4GeneratorAction>::Geant4Handle(Geant4Kernel& kernel, const char* type_name, bool shared) { + value = _create_share(kernel,&Geant4Kernel::generatorAction,type_name,"Geant4SharedGeneratorAction",shared,(handled_type*)0); + } + + template <> + Geant4Handle<Geant4TrackingAction>::Geant4Handle(Geant4Kernel& kernel, const string& type_name, bool shared) { + value = _create_share(kernel,&Geant4Kernel::trackingAction,type_name,"Geant4SharedTrackingAction",shared,(handled_type*)0); + } + template <> + Geant4Handle<Geant4TrackingAction>::Geant4Handle(Geant4Kernel& kernel, const char* type_name, bool shared) { + value = _create_share(kernel,&Geant4Kernel::trackingAction,type_name,"Geant4SharedTrackingAction",shared,(handled_type*)0); + } + + template <> + Geant4Handle<Geant4SteppingAction>::Geant4Handle(Geant4Kernel& kernel, const string& type_name, bool shared) { + value = _create_share(kernel,&Geant4Kernel::steppingAction,type_name,"Geant4SharedSteppingAction",shared,(handled_type*)0); + } + template <> + Geant4Handle<Geant4SteppingAction>::Geant4Handle(Geant4Kernel& kernel, const char* type_name, bool shared) { + value = _create_share(kernel,&Geant4Kernel::steppingAction,type_name,"Geant4SharedSteppingAction",shared,(handled_type*)0); + } + + template <> + Geant4Handle<Geant4StackingAction>::Geant4Handle(Geant4Kernel& kernel, const string& type_name, bool shared) { + value = _create_share(kernel,&Geant4Kernel::stackingAction,type_name,"Geant4SharedStackingAction",shared,(handled_type*)0); + } + template <> + Geant4Handle<Geant4StackingAction>::Geant4Handle(Geant4Kernel& kernel, const char* type_name, bool shared) { + value = _create_share(kernel,&Geant4Kernel::stackingAction,type_name,"Geant4SharedStackingAction",shared,(handled_type*)0); + } + template <> Geant4Handle<Geant4Sensitive>::Geant4Handle(Geant4Kernel& kernel, const string& type_name, - const string& detector) { + const string& detector, bool /* shared */) { try { - Geant4Context ctxt(&kernel); + Geant4Context* ctxt = kernel.workerContext(); TypeName typ = TypeName::split(type_name); Geometry::LCDD& lcdd = kernel.lcdd(); Geometry::DetElement det = lcdd.detector(detector); - Geant4Sensitive* object = PluginService::Create<Geant4Sensitive*>(typ.first, &ctxt, typ.second, &det, &lcdd); + Geant4Sensitive* object = PluginService::Create<Geant4Sensitive*>(typ.first, ctxt, typ.second, &det, &lcdd); if (object) { value = object; return; @@ -221,32 +294,36 @@ template <typename TYPE> Geant4Handle<TYPE>& Geant4Handle<TYPE>::operator=(TYPE* catch (...) { printout(ERROR, "Geant4Handle<Geant4Sensitive>", "Exception: Unknown exception"); } - throw runtime_error( - format("Geant4Handle<Geant4Sensitive>", "Failed to create sensitive object of type %s for detector %s!", + throw runtime_error(format("Geant4Handle<Geant4Sensitive>", + "Failed to create sensitive object of type %s for detector %s!", type_name.c_str(), detector.c_str())); } -template class Geant4Handle<Geant4Action> ; -template class Geant4Handle<Geant4Filter> ; -template class Geant4Handle<Geant4Sensitive> ; -template class Geant4Handle<Geant4ActionPhase> ; -template class Geant4Handle<Geant4PhaseAction> ; -template class Geant4Handle<Geant4GeneratorAction> ; -template class Geant4Handle<Geant4RunAction> ; -template class Geant4Handle<Geant4EventAction> ; -template class Geant4Handle<Geant4TrackingAction> ; -template class Geant4Handle<Geant4SteppingAction> ; -template class Geant4Handle<Geant4StackingAction> ; -template class Geant4Handle<Geant4PhysicsList> ; - -template class Geant4Handle<Geant4GeneratorActionSequence> ; -template class Geant4Handle<Geant4PhysicsListActionSequence> ; -template class Geant4Handle<Geant4RunActionSequence> ; -template class Geant4Handle<Geant4EventActionSequence> ; -template class Geant4Handle<Geant4TrackingActionSequence> ; -template class Geant4Handle<Geant4SteppingActionSequence> ; -template class Geant4Handle<Geant4StackingActionSequence> ; -template class Geant4Handle<Geant4SensDetActionSequence> ; + template class Geant4Handle<Geant4Action>; + template class Geant4Handle<Geant4Filter>; + template class Geant4Handle<Geant4Sensitive>; + template class Geant4Handle<Geant4ActionPhase>; + template class Geant4Handle<Geant4PhaseAction>; + template class Geant4Handle<Geant4GeneratorAction>; + template class Geant4Handle<Geant4RunAction>; + template class Geant4Handle<Geant4EventAction>; + template class Geant4Handle<Geant4TrackingAction>; + template class Geant4Handle<Geant4SteppingAction>; + template class Geant4Handle<Geant4StackingAction>; + template class Geant4Handle<Geant4DetectorConstruction>; + template class Geant4Handle<Geant4PhysicsList>; + template class Geant4Handle<Geant4UserInitialization>; + + template class Geant4Handle<Geant4GeneratorActionSequence>; + template class Geant4Handle<Geant4PhysicsListActionSequence>; + template class Geant4Handle<Geant4RunActionSequence>; + template class Geant4Handle<Geant4EventActionSequence>; + template class Geant4Handle<Geant4TrackingActionSequence>; + template class Geant4Handle<Geant4SteppingActionSequence>; + template class Geant4Handle<Geant4StackingActionSequence>; + template class Geant4Handle<Geant4SensDetActionSequence>; + template class Geant4Handle<Geant4UserInitializationSequence>; + template class Geant4Handle<Geant4DetectorConstructionSequence>; } } diff --git a/DDG4/src/Geant4HitCollection.cpp b/DDG4/src/Geant4HitCollection.cpp index 1b1a2f28b608c24c9c853af7412c7b4765ba4ba7..aa9cfc5f897ca564d6f77d688501f7b6de1ec660 100644 --- a/DDG4/src/Geant4HitCollection.cpp +++ b/DDG4/src/Geant4HitCollection.cpp @@ -21,7 +21,7 @@ using namespace DD4hep; using namespace DD4hep::Simulation; -static G4Allocator<Geant4HitWrapper> HitWrapperAllocator; +G4ThreadLocal G4Allocator<Geant4HitWrapper>* HitWrapperAllocator = 0; Geant4HitWrapper::InvalidHit::~InvalidHit() { } @@ -47,12 +47,15 @@ Geant4HitWrapper::~Geant4HitWrapper() { /// Geant4 required object allocator void* Geant4HitWrapper::operator new(size_t) { - return HitWrapperAllocator.MallocSingle(); + if ( HitWrapperAllocator ) + return HitWrapperAllocator->MallocSingle(); + HitWrapperAllocator = new G4Allocator<Geant4HitWrapper>; + return HitWrapperAllocator->MallocSingle(); } /// Geat4 required object destroyer void Geant4HitWrapper::operator delete(void *p) { - HitWrapperAllocator.FreeSingle((Geant4HitWrapper*) p); + HitWrapperAllocator->FreeSingle((Geant4HitWrapper*) p); } /// Pointer/Object release diff --git a/DDG4/src/Geant4Hits.cpp b/DDG4/src/Geant4Hits.cpp index 86a96f1ec627a0257348df250d82968351a87737..acf871076a59d60a54f9ac20bd4bf6f0d575a1b7 100644 --- a/DDG4/src/Geant4Hits.cpp +++ b/DDG4/src/Geant4Hits.cpp @@ -28,6 +28,10 @@ using namespace std; using namespace DD4hep::Simulation; +G4ThreadLocal G4Allocator<Geant4TrackerHit>* TrackerHitAllocator = 0; +G4ThreadLocal G4Allocator<Geant4CalorimeterHit>* CalorimeterHitAllocator = 0; + + /// Check if the Geant4 track is a Geantino bool Geant4Hit::isGeantino(G4Track* track) { if (track) { @@ -50,8 +54,6 @@ Geant4Hit::Contribution Geant4Hit::extractContribution(G4Step* step) { return contrib; } -static G4Allocator<Geant4TrackerHit> TrackerHitAllocator; - /// Default constructor Geant4TrackerHit::Geant4TrackerHit() : Geant4Hit(), position(), momentum(), length(0.0), truth(), energyDeposit(0.0) { @@ -103,16 +105,17 @@ Geant4TrackerHit& Geant4TrackerHit::storePoint(G4Step* step, G4StepPoint* pnt) { /// Geant4 required object allocator void* Geant4TrackerHit::operator new(size_t) { - return TrackerHitAllocator.MallocSingle(); + if ( TrackerHitAllocator ) + return TrackerHitAllocator->MallocSingle(); + TrackerHitAllocator = new G4Allocator<Geant4TrackerHit>; + return TrackerHitAllocator->MallocSingle(); } /// Geat4 required object destroyer void Geant4TrackerHit::operator delete(void *p) { - TrackerHitAllocator.FreeSingle((Geant4TrackerHit*) p); + TrackerHitAllocator->FreeSingle((Geant4TrackerHit*) p); } -static G4Allocator<Geant4CalorimeterHit> CalorimeterHitAllocator; - /// Standard constructor Geant4CalorimeterHit::Geant4CalorimeterHit(const Position& pos) : Geant4Hit(), position(pos), truth(), energyDeposit(0) { @@ -120,11 +123,14 @@ Geant4CalorimeterHit::Geant4CalorimeterHit(const Position& pos) /// Geant4 required object allocator void* Geant4CalorimeterHit::operator new(size_t) { - return CalorimeterHitAllocator.MallocSingle(); + if ( CalorimeterHitAllocator ) + return CalorimeterHitAllocator->MallocSingle(); + CalorimeterHitAllocator = new G4Allocator<Geant4CalorimeterHit>; + return CalorimeterHitAllocator->MallocSingle(); } /// Geat4 required object destroyer void Geant4CalorimeterHit::operator delete(void *p) { - CalorimeterHitAllocator.FreeSingle((Geant4CalorimeterHit*) p); + CalorimeterHitAllocator->FreeSingle((Geant4CalorimeterHit*) p); } diff --git a/DDG4/src/Geant4InputHandling.cpp b/DDG4/src/Geant4InputHandling.cpp index 82dc8df2b49564c3491744b9de0d30d628db21a1..3f7bd611af3d61d1d552ce711ecd9afe97f13f1c 100644 --- a/DDG4/src/Geant4InputHandling.cpp +++ b/DDG4/src/Geant4InputHandling.cpp @@ -31,7 +31,6 @@ #include <cmath> using namespace std; -using namespace CLHEP; using namespace DD4hep; using namespace DD4hep::Simulation; diff --git a/DDG4/src/Geant4Kernel.cpp b/DDG4/src/Geant4Kernel.cpp index 6dccbc048d7e7edd7e95c3d8b59af68ea10bdeec..dcadd83396e347ae64e3eccd5513c39775b3bbd5 100644 --- a/DDG4/src/Geant4Kernel.cpp +++ b/DDG4/src/Geant4Kernel.cpp @@ -19,6 +19,7 @@ #include "DD4hep/InstanceCount.h" #include "DDG4/Geant4Kernel.h" +#include "DDG4/Geant4Context.h" #include "DDG4/Geant4ActionPhase.h" #include "DDG4/Geant4RunAction.h" @@ -28,10 +29,16 @@ #include "DDG4/Geant4TrackingAction.h" #include "DDG4/Geant4StackingAction.h" #include "DDG4/Geant4GeneratorAction.h" +#include "DDG4/Geant4DetectorConstruction.h" +#include "DDG4/Geant4UserInitialization.h" #include "DDG4/Geant4SensDetAction.h" // Geant4 include files +#ifdef G4MULTITHREADED +#include "G4MTRunManager.hh" +#else #include "G4RunManager.hh" +#endif #include "G4UIdirectory.hh" // C/C++ include files @@ -61,9 +68,9 @@ Geant4Kernel::PhaseSelector& Geant4Kernel::PhaseSelector::operator=(const PhaseS /// Phase access to the map Geant4ActionPhase& Geant4Kernel::PhaseSelector::operator[](const std::string& nam) const { - Geant4ActionPhase* phase = m_kernel->getPhase(nam); - if (phase) { - return *phase; + Geant4ActionPhase* action_phase = m_kernel->getPhase(nam); + if ( action_phase ) { + return *action_phase; } throw runtime_error(format("Geant4Kernel", "Attempt to access the nonexisting phase '%s'", nam.c_str())); } @@ -71,44 +78,73 @@ Geant4ActionPhase& Geant4Kernel::PhaseSelector::operator[](const std::string& na /// Standard constructor Geant4Kernel::Geant4Kernel(LCDD& lcdd_ref) : m_runManager(0), m_generatorAction(0), m_runAction(0), m_eventAction(0), - m_trackingAction(0), m_steppingAction(0), m_stackingAction(0), m_sensDetActions(0), - m_physicsList(0), m_lcdd(lcdd_ref), phase(this) { -#if 0 - registerSequence(m_runAction, "RunAction"); - registerSequence(m_eventAction, "EventAction"); - registerSequence(m_steppingAction, "SteppingAction"); - registerSequence(m_trackingAction, "TrackingAction"); - registerSequence(m_stackingAction, "StackingAction"); - registerSequence(m_generatorAction,"GeneratorAction"); -#endif + m_trackingAction(0), m_steppingAction(0), m_stackingAction(0), m_constructionAction(0), + m_sensDetActions(0), m_physicsList(0), m_userInit(0), m_lcdd(lcdd_ref), + m_numThreads(0), m_id(pthread_self()), m_master(this), phase(this) +{ m_sensDetActions = new Geant4SensDetSequences(); m_lcdd.addExtension < Geant4Kernel > (this); + m_ident = -1; declareProperty("UI",m_uiName); - declareProperty("OutputLevel",m_outputLevel = DEBUG); - declareProperty("NumEvents",m_numEvent = 10); - declareProperty("OutputLevels",m_clientLevels); + declareProperty("OutputLevel", m_outputLevel = DEBUG); + declareProperty("NumEvents", m_numEvent = 10); + declareProperty("OutputLevels", m_clientLevels); + declareProperty("NumberOfThreads",m_numThreads); + //declareProperty("MultiThreaded", m_multiThreaded=false); m_controlName = "/ddg4/"; m_control = new G4UIdirectory(m_controlName.c_str()); - m_control->SetGuidance("Control for all named Geant4 actions"); + m_control->SetGuidance("Control for named Geant4 actions"); + m_threadContext = new Geant4Context(this); + InstanceCount::increment(this); +} + +/// Standard constructor +Geant4Kernel::Geant4Kernel(LCDD& lcdd_ref, Geant4Kernel* m, unsigned long ident) + : m_runManager(0), m_generatorAction(0), m_runAction(0), m_eventAction(0), + m_trackingAction(0), m_steppingAction(0), m_stackingAction(0), m_constructionAction(0), + m_sensDetActions(0), m_physicsList(0), m_userInit(0), m_lcdd(lcdd_ref), m_id(ident), + m_master(m), phase(this) +{ + char text[64]; + m_numThreads = 1; + //m_multiThreaded = m_master->m_multiThreaded; + m_ident = m_master->m_workers.size(); + m_sensDetActions = new Geant4SensDetSequences(); + declareProperty("UI",m_uiName = m_master->m_uiName); + declareProperty("OutputLevel", m_outputLevel = m_master->m_outputLevel); + declareProperty("OutputLevels",m_clientLevels = m_master->m_clientLevels); + ::snprintf(text,sizeof(text),"/ddg4.%d/",(int)(m_master->m_workers.size())); + m_controlName = text; + m_control = new G4UIdirectory(m_controlName.c_str()); + m_control->SetGuidance("Control for thread specific Geant4 actions"); + m_threadContext = new Geant4Context(this); InstanceCount::increment(this); } /// Default destructor Geant4Kernel::~Geant4Kernel() { + destroyObjects(m_workers)(); + if ( isMaster() ) { + releaseObjects(m_globalFilters)(); + releaseObjects(m_globalActions)(); + } destroyPhases(); - for_each(m_globalFilters.begin(), m_globalFilters.end(), releaseObjects(m_globalFilters)); - for_each(m_globalActions.begin(), m_globalActions.end(), releaseObjects(m_globalActions)); deletePtr (m_runManager); releasePtr (m_physicsList); + releasePtr (m_constructionAction); releasePtr (m_stackingAction); releasePtr (m_steppingAction); releasePtr (m_trackingAction); releasePtr (m_eventAction); releasePtr (m_generatorAction); releasePtr (m_runAction); + releasePtr (m_userInit); deletePtr (m_sensDetActions); - m_lcdd.removeExtension < Geant4Kernel > (false); - m_lcdd.destroyInstance(); + deletePtr (m_threadContext); + if ( isMaster() ) { + m_lcdd.removeExtension < Geant4Kernel > (false); + m_lcdd.destroyInstance(); + } InstanceCount::decrement(this); } @@ -118,10 +154,58 @@ Geant4Kernel& Geant4Kernel::instance(LCDD& lcdd) { return obj; } +/// Accessof the Geant4Kernel object from the LCDD reference extension (if present and registered) +Geant4Kernel& Geant4Kernel::access(LCDD& lcdd) { + Geant4Kernel* kernel = lcdd.extension<Geant4Kernel>(); + if (!kernel) { + throw runtime_error(format("Geant4Kernel", "DDG4: The LCDD object has no registered " + "extension of type Geant4Kernel [No-Extension]")); + } + return *kernel; +} + +Geant4Context* Geant4Kernel::workerContext() { + if ( m_threadContext ) return m_threadContext; + throw runtime_error(format("Geant4Kernel", "DDG4: Master kernel object has no thread context! [Invalid Handle]")); +} + +/// Create identified worker instance +Geant4Kernel& Geant4Kernel::createWorker() { + if ( isMaster() ) { + unsigned long identifier = ::pthread_self(); + Geant4Kernel* w = new Geant4Kernel(m_lcdd, this, identifier); + m_workers[identifier] = w; + printout(INFO,"Geant4Kernel","+++ Created worker instance id=%ul",identifier); + return *w; + } + throw runtime_error(format("Geant4Kernel", "DDG4: Only the master instance may create workers.")); +} + +/// Access worker instance by it's identifier +Geant4Kernel& Geant4Kernel::worker(unsigned long identifier) { + Workers::iterator i = m_workers.find(identifier); + if ( i != m_workers.end() ) { + return *((*i).second); + } + else if ( !isMultiThreaded() ) { + unsigned long self = ::pthread_self(); + if ( identifier == self ) { + return *this; + } + } + throw runtime_error(format("Geant4Kernel", "DDG4: The Kernel object 0x%p does not exists!",(void*)identifier)); +} + +/// Access number of workers +int Geant4Kernel::numWorkers() const { + return m_workers.size(); +} + void Geant4Kernel::printProperties() const { - printout(ALWAYS,"Geant4Kernel","OutputLevel: %d",m_outputLevel); - printout(ALWAYS,"Geant4Kernel","UI: %s",m_uiName.c_str()); + printout(ALWAYS,"Geant4Kernel","OutputLevel: %d", m_outputLevel); + printout(ALWAYS,"Geant4Kernel","UI: %s", m_uiName.c_str()); printout(ALWAYS,"Geant4Kernel","NumEvents: %ld",m_numEvent); + printout(ALWAYS,"Geant4Kernel","NumThreads: %d", m_numThreads); for(ClientOutputLevels::const_iterator i=m_clientLevels.begin(); i!=m_clientLevels.end();++i) { printout(ALWAYS,"Geant4Kernel","OutputLevel[%s]: %d",(*i).first.c_str(),(*i).second); } @@ -137,16 +221,6 @@ DD4hep::Property& Geant4Kernel::property(const std::string& name) { return properties()[name]; } -/// Accessof the Geant4Kernel object from the LCDD reference extension (if present and registered) -Geant4Kernel& Geant4Kernel::access(LCDD& lcdd) { - Geant4Kernel* kernel = lcdd.extension<Geant4Kernel>(); - if (!kernel) { - throw runtime_error(format("Geant4Kernel", "DDG4: The LCDD object has no registered " - "extension of type Geant4Kernel [No-Extension]")); - } - return *kernel; -} - /// Fill cache with the global output level of a named object. Must be set before instantiation void Geant4Kernel::setOutputLevel(const std::string object, PrintLevel new_level) { m_clientLevels[object] = new_level; @@ -168,9 +242,30 @@ DD4hep::PrintLevel Geant4Kernel::setOutputLevel(PrintLevel new_level) { /// Access to the Geant4 run manager G4RunManager& Geant4Kernel::runManager() { - if (m_runManager) + if ( m_runManager ) { return *m_runManager; - return *(m_runManager = new G4RunManager); + } + else if ( isMaster() ) { +#ifdef G4MULTITHREADED + if ( m_numThreads > 0 ) { + printout(WARNING,"Geant4Kernel","+++ Multi-threaded mode requested with %d worker threads.",m_numThreads); + G4MTRunManager* run_mgr = new G4MTRunManager; + run_mgr->SetNumberOfThreads(m_numThreads); + m_runManager = run_mgr; + return *m_runManager; + } +#endif + if ( m_numThreads > 0 ) { + printout(WARNING,"Geant4Kernel","+++ Multi-threaded mode requested, " + "but not supported by this compilation of Geant4."); + printout(WARNING,"Geant4Kernel","+++ Falling back to single threaded mode."); + m_numThreads = 0; + } + return *(m_runManager = new G4RunManager); + } + throw runtime_error(format("Geant4Kernel", + "DDG4: Only the master thread may instantiate " + "a G4RunManager object!")); } /// Construct detector geometry using lcdd plugin @@ -186,17 +281,17 @@ void Geant4Kernel::loadXML(const char* fname) { m_lcdd.apply("DD4hepXMLLoader", 1, (char**) args); } -void Geant4Kernel::configure() { - Geant4Exec::configure(*this); +int Geant4Kernel::configure() { + return Geant4Exec::configure(*this); } -void Geant4Kernel::initialize() { - Geant4Exec::initialize(*this); +int Geant4Kernel::initialize() { + return Geant4Exec::initialize(*this); } -void Geant4Kernel::run() { +int Geant4Kernel::run() { try { - Geant4Exec::run(*this); + return Geant4Exec::run(*this); } catch(const exception& e) { printout(FATAL,"Geant4Kernel","+++ Exception while simulating:%s",e.what()); @@ -204,20 +299,22 @@ void Geant4Kernel::run() { catch(...) { printout(FATAL,"Geant4Kernel","+++ UNKNOWN exception while simulating."); } + return 0; } -void Geant4Kernel::runEvents(int num_events) { +int Geant4Kernel::runEvents(int num_events) { m_numEvent = num_events; - Geant4Exec::run(*this); + return Geant4Exec::run(*this); } -void Geant4Kernel::terminate() { +int Geant4Kernel::terminate() { Geant4Exec::terminate(*this); destroyPhases(); for_each(m_globalFilters.begin(), m_globalFilters.end(), releaseObjects(m_globalFilters)); for_each(m_globalActions.begin(), m_globalActions.end(), releaseObjects(m_globalActions)); deletePtr (m_runManager); releasePtr (m_physicsList); + releasePtr (m_constructionAction); releasePtr (m_stackingAction); releasePtr (m_steppingAction); releasePtr (m_trackingAction); @@ -226,12 +323,12 @@ void Geant4Kernel::terminate() { releasePtr (m_runAction); deletePtr (m_sensDetActions); //return *this; + return 1; } template <class C> bool Geant4Kernel::registerSequence(C*& seq, const std::string& name) { if (!name.empty()) { - Geant4Context ctxt(this); - seq = new C(&ctxt, name); + seq = new C(workerContext(), name); seq->installMessengers(); return true; } @@ -338,8 +435,7 @@ Geant4ActionPhase* Geant4Kernel::addPhase(const std::string& nam, const type_inf const type_info& arg2, bool throw_on_exist) { Phases::const_iterator i = m_phases.find(nam); if (i == m_phases.end()) { - Geant4Context ctxt(this); - Geant4ActionPhase* p = new Geant4ActionPhase(&ctxt, nam, arg0, arg1, arg2); + Geant4ActionPhase* p = new Geant4ActionPhase(workerContext(), nam, arg0, arg1, arg2); m_phases.insert(make_pair(nam, p)); return p; } @@ -408,6 +504,13 @@ Geant4StackingActionSequence* Geant4Kernel::stackingAction(bool create) { return m_stackingAction; } +/// Access detector construcion action sequence (geometry+sensitives+field) +Geant4DetectorConstructionSequence* Geant4Kernel::detectorConstruction(bool create) { + if (!m_constructionAction && create) + registerSequence(m_constructionAction, "StackingAction"); + return m_constructionAction; +} + /// Access to the sensitive detector sequences from the kernel object Geant4SensDetSequences& Geant4Kernel::sensitiveActions() const { return *m_sensDetActions; @@ -416,10 +519,10 @@ Geant4SensDetSequences& Geant4Kernel::sensitiveActions() const { /// Access to the sensitive detector action from the kernel object Geant4SensDetActionSequence* Geant4Kernel::sensitiveAction(const string& nam) { Geant4SensDetActionSequence* ptr = m_sensDetActions->find(nam); - if (ptr) + if (ptr) { return ptr; - Geant4Context ctxt(this); - ptr = new Geant4SensDetActionSequence(&ctxt, nam); + } + ptr = new Geant4SensDetActionSequence(workerContext(), nam); m_sensDetActions->insert(nam, ptr); return ptr; } @@ -430,3 +533,16 @@ Geant4PhysicsListActionSequence* Geant4Kernel::physicsList(bool create) { registerSequence(m_physicsList, "PhysicsList"); return m_physicsList; } + +/// Access to the physics list +Geant4UserInitializationSequence* Geant4Kernel::userInitialization(bool create) { + if ( !m_userInit && create ) { + if ( isMaster() ) + registerSequence(m_userInit, "UserInitialization"); + else + throw runtime_error(format("Geant4Kernel", + "DDG4: Only the master thread may initialize " + "a user initialization object!")); + } + return m_userInit; +} diff --git a/DDG4/src/Geant4OutputAction.cpp b/DDG4/src/Geant4OutputAction.cpp index 7bad4ffe14bedca23a709852e21963f7f0c87da2..016afbc1e643a8b078482940946297ecbf27afe3 100644 --- a/DDG4/src/Geant4OutputAction.cpp +++ b/DDG4/src/Geant4OutputAction.cpp @@ -34,8 +34,8 @@ Geant4OutputAction::Geant4OutputAction(Geant4Context* ctxt, const string& nam) InstanceCount::increment(this); declareProperty("Output", m_output); declareProperty("HandleErrorsAsFatal", m_errorFatal=true); - context()->runAction().callAtBegin(this, &Geant4OutputAction::beginRun); - context()->runAction().callAtEnd(this, &Geant4OutputAction::endRun); + //ctxt->runAction().callAtBegin(this, &Geant4OutputAction::beginRun); + //ctxt->runAction().callAtEnd(this, &Geant4OutputAction::endRun); } /// Default destructor @@ -43,6 +43,13 @@ Geant4OutputAction::~Geant4OutputAction() { InstanceCount::decrement(this); } +/// Set or update client for the use in a new thread fiber with seperate action sequences +void Geant4OutputAction::configureFiber(Geant4Context* thread_ctxt) { + Geant4EventAction::configureFiber(thread_ctxt); + thread_ctxt->runAction().callAtBegin(this, &Geant4OutputAction::beginRun); + thread_ctxt->runAction().callAtEnd(this, &Geant4OutputAction::endRun); +} + /// begin-of-event callback void Geant4OutputAction::begin(const G4Event* /* event */) { } diff --git a/DDG4/src/Geant4Particle.cpp b/DDG4/src/Geant4Particle.cpp index f2a82824c462fcbb52480e55fa5e507b9298a98b..9ba33508f2caa98918efe7721a5e648a10975d46 100644 --- a/DDG4/src/Geant4Particle.cpp +++ b/DDG4/src/Geant4Particle.cpp @@ -27,7 +27,6 @@ #include <iostream> -using namespace CLHEP; using namespace DD4hep; using namespace DD4hep::Simulation; typedef ReferenceBitMask<int> PropertyMask; @@ -156,7 +155,7 @@ const G4ParticleDefinition* Geant4ParticleHandle::definition() const { G4ParticleTable* tab = G4ParticleTable::GetParticleTable(); G4ParticleDefinition* def = tab->FindParticle(particle->pdgID); if ( 0 == def && 0 == particle->pdgID ) { - if ( fabs(particle->charge) < 0.001 ) + if ( 0 == particle->charge ) return G4Geantino::Definition(); return G4ChargedGeantino::Definition(); } diff --git a/DDG4/src/Geant4RunAction.cpp b/DDG4/src/Geant4RunAction.cpp index cb2045c7cffb48a7ba24e217d5522a98eba9c37e..58b049a6cba248030c18d7d381fd78bd5c46e019 100644 --- a/DDG4/src/Geant4RunAction.cpp +++ b/DDG4/src/Geant4RunAction.cpp @@ -15,14 +15,21 @@ // Framework include files #include "DD4hep/InstanceCount.h" #include "DDG4/Geant4RunAction.h" - +// Geant4 headers +#include "G4Threading.hh" +#include "G4AutoLock.hh" // C/C++ include files #include <stdexcept> +using namespace std; using namespace DD4hep::Simulation; +namespace { + G4Mutex action_mutex=G4MUTEX_INITIALIZER; +} + /// Standard constructor -Geant4RunAction::Geant4RunAction(Geant4Context* ctxt, const std::string& nam) +Geant4RunAction::Geant4RunAction(Geant4Context* ctxt, const string& nam) : Geant4Action(ctxt, nam) { InstanceCount::increment(this); } @@ -41,7 +48,55 @@ void Geant4RunAction::end(const G4Run*) { } /// Standard constructor -Geant4RunActionSequence::Geant4RunActionSequence(Geant4Context* ctxt, const std::string& nam) +Geant4SharedRunAction::Geant4SharedRunAction(Geant4Context* ctxt, const string& nam) + : Geant4RunAction(ctxt, nam) +{ + InstanceCount::increment(this); +} + +/// Default destructor +Geant4SharedRunAction::~Geant4SharedRunAction() { + releasePtr(m_action); + InstanceCount::decrement(this); +} + +/// Set or update client for the use in a new thread fiber +void Geant4SharedRunAction::configureFiber(Geant4Context* thread_context) { + m_action->configureFiber(thread_context); +} + +/// Underlying object to be used during the execution of this thread +void Geant4SharedRunAction::use(Geant4RunAction* action) { + if (action) { + action->addRef(); + m_action = action; + return; + } + throw runtime_error("Geant4SharedRunAction: Attempt to use invalid actor!"); +} + +/// Begin-of-run callback +void Geant4SharedRunAction::begin(const G4Run* run) { + if ( m_action ) { + G4AutoLock protection_lock(&action_mutex); { + ContextSwap swap(m_action,context()); + m_action->begin(run); + } + } +} + +/// End-of-run callback +void Geant4SharedRunAction::end(const G4Run* run) { + if ( m_action ) { + G4AutoLock protection_lock(&action_mutex); { + ContextSwap swap(m_action,context()); + m_action->end(run); + } + } +} + +/// Standard constructor +Geant4RunActionSequence::Geant4RunActionSequence(Geant4Context* ctxt, const string& nam) : Geant4Action(ctxt, nam) { m_needsControl = true; InstanceCount::increment(this); @@ -56,26 +111,43 @@ Geant4RunActionSequence::~Geant4RunActionSequence() { InstanceCount::decrement(this); } +/// Set or update client context +void Geant4RunActionSequence::updateContext(Geant4Context* ctxt) { + m_context = ctxt; + m_actors.updateContext(ctxt); +} + +/// Set or update client for the use in a new thread fiber +void Geant4RunActionSequence::configureFiber(Geant4Context* thread_context) { + m_actors(&Geant4Action::configureFiber, thread_context); +} + +/// Get an action by name +Geant4RunAction* Geant4RunActionSequence::get(const string& nam) const { + return m_actors.get(FindByName(TypeName::split(nam).second)); +} + /// Add an actor responding to all callbacks. Sequence takes ownership. void Geant4RunActionSequence::adopt(Geant4RunAction* action) { if (action) { + G4AutoLock protection_lock(&action_mutex); action->addRef(); m_actors.add(action); return; } - throw std::runtime_error("Geant4RunActionSequence: Attempt to add invalid actor!"); + throw runtime_error("Geant4RunActionSequence: Attempt to add invalid actor!"); } /// Pre-track action callback void Geant4RunActionSequence::begin(const G4Run* run) { - m_actors(ContextUpdate(context())); + G4AutoLock protection_lock(&action_mutex); m_actors(&Geant4RunAction::begin, run); m_begin(run); } /// Post-track action callback void Geant4RunActionSequence::end(const G4Run* run) { + G4AutoLock protection_lock(&action_mutex); m_end(run); m_actors(&Geant4RunAction::end, run); - m_actors(ContextUpdate()); } diff --git a/DDG4/src/Geant4SensDetAction.cpp b/DDG4/src/Geant4SensDetAction.cpp index 04a9c098b412c67290800276b3eefb9a514aba29..05552e435fc86ef9c4ae0cca76bd7b37ebbb4384 100644 --- a/DDG4/src/Geant4SensDetAction.cpp +++ b/DDG4/src/Geant4SensDetAction.cpp @@ -35,6 +35,7 @@ using namespace std; using namespace DD4hep; using namespace DD4hep::Simulation; +#if 0 namespace { Geant4ActionSD* _getSensitiveDetector(const string& name) { G4SDManager* mgr = G4SDManager::GetSDMpointer(); @@ -55,6 +56,7 @@ namespace { return action_sd; } } +#endif /// Standard action constructor Geant4ActionSD::Geant4ActionSD(const std::string& nam) @@ -238,6 +240,13 @@ Geant4SensDetActionSequence::~Geant4SensDetActionSequence() { InstanceCount::decrement(this); } +/// Set or update client context +void Geant4SensDetActionSequence::updateContext(Geant4Context* ctxt) { + m_context = ctxt; + m_actors.updateContext(ctxt); + m_filters.updateContext(ctxt); +} + /// Add an actor responding to all callbacks. Sequence takes ownership. void Geant4SensDetActionSequence::adoptFilter(Geant4Action* action) { Geant4Filter* filter = dynamic_cast<Geant4Filter*>(action); @@ -338,7 +347,6 @@ bool Geant4SensDetActionSequence::process(G4Step* step, G4TouchableHistory* hist */ void Geant4SensDetActionSequence::begin(G4HCofThisEvent* hce) { m_hce = hce; - m_actors(ContextUpdate(context())); for (size_t count = 0; count < m_collections.size(); ++count) { const HitCollection& cr = m_collections[count]; Geant4HitCollection* c = (*cr.second.second)(name(), cr.first, cr.second.first); @@ -353,7 +361,6 @@ void Geant4SensDetActionSequence::begin(G4HCofThisEvent* hce) { void Geant4SensDetActionSequence::end(G4HCofThisEvent* hce) { m_end(hce); m_actors(&Geant4Sensitive::end, hce); - m_actors(ContextUpdate()); // G4HCofThisEvent must be availible until end-event. m_hce = 0; } diff --git a/DDG4/src/Geant4StackingAction.cpp b/DDG4/src/Geant4StackingAction.cpp index 839509afdaca9b92057623d300627c32b4707154..bd675c2bd80867cf9453ccf208945f68688c5a35 100644 --- a/DDG4/src/Geant4StackingAction.cpp +++ b/DDG4/src/Geant4StackingAction.cpp @@ -15,14 +15,21 @@ // Framework include files #include "DD4hep/InstanceCount.h" #include "DDG4/Geant4StackingAction.h" +// Geant4 headers +#include "G4Threading.hh" +#include "G4AutoLock.hh" // C/C++ include files #include <stdexcept> +using namespace std; using namespace DD4hep::Simulation; +namespace { + G4Mutex action_mutex=G4MUTEX_INITIALIZER; +} /// Standard constructor -Geant4StackingAction::Geant4StackingAction(Geant4Context* ctxt, const std::string& nam) +Geant4StackingAction::Geant4StackingAction(Geant4Context* ctxt, const string& nam) : Geant4Action(ctxt, nam) { InstanceCount::increment(this); } @@ -33,7 +40,55 @@ Geant4StackingAction::~Geant4StackingAction() { } /// Standard constructor -Geant4StackingActionSequence::Geant4StackingActionSequence(Geant4Context* ctxt, const std::string& nam) +Geant4SharedStackingAction::Geant4SharedStackingAction(Geant4Context* ctxt, const string& nam) + : Geant4StackingAction(ctxt, nam) +{ + InstanceCount::increment(this); +} + +/// Default destructor +Geant4SharedStackingAction::~Geant4SharedStackingAction() { + releasePtr(m_action); + InstanceCount::decrement(this); +} + +/// Set or update client for the use in a new thread fiber +void Geant4SharedStackingAction::configureFiber(Geant4Context* thread_context) { + m_action->configureFiber(thread_context); +} + +/// Underlying object to be used during the execution of this thread +void Geant4SharedStackingAction::use(Geant4StackingAction* action) { + if (action) { + action->addRef(); + m_action = action; + return; + } + throw runtime_error("Geant4SharedStackingAction: Attempt to use invalid actor!"); +} + +/// Begin-of-stacking callback +void Geant4SharedStackingAction::newStage() { + if ( m_action ) { + G4AutoLock protection_lock(&action_mutex); { + ContextSwap swap(m_action,context()); + m_action->newStage(); + } + } +} + +/// End-of-stacking callback +void Geant4SharedStackingAction::prepare() { + if ( m_action ) { + G4AutoLock protection_lock(&action_mutex); { + ContextSwap swap(m_action,context()); + m_action->prepare(); + } + } +} + +/// Standard constructor +Geant4StackingActionSequence::Geant4StackingActionSequence(Geant4Context* ctxt, const string& nam) : Geant4Action(ctxt, nam) { m_needsControl = true; InstanceCount::increment(this); @@ -55,12 +110,27 @@ void Geant4StackingActionSequence::adopt(Geant4StackingAction* action) { m_actors.add(action); return; } - throw std::runtime_error("Geant4StackingActionSequence: Attempt to add invalid actor!"); + throw runtime_error("Geant4StackingActionSequence: Attempt to add invalid actor!"); +} + +/// Set or update client context +void Geant4StackingActionSequence::updateContext(Geant4Context* ctxt) { + m_context = ctxt; + m_actors.updateContext(ctxt); +} + +/// Set or update client for the use in a new thread fiber +void Geant4StackingActionSequence::configureFiber(Geant4Context* thread_context) { + m_actors(&Geant4Action::configureFiber, thread_context); +} + +/// Get an action by name +Geant4StackingAction* Geant4StackingActionSequence::get(const string& nam) const { + return m_actors.get(FindByName(TypeName::split(nam).second)); } /// Pre-track action callback void Geant4StackingActionSequence::newStage() { - m_actors(ContextUpdate(context())); m_actors(&Geant4StackingAction::newStage); m_newStage(); } @@ -69,5 +139,4 @@ void Geant4StackingActionSequence::newStage() { void Geant4StackingActionSequence::prepare() { m_actors(&Geant4StackingAction::prepare); m_prepare(); - m_actors(ContextUpdate()); } diff --git a/DDG4/src/Geant4SteppingAction.cpp b/DDG4/src/Geant4SteppingAction.cpp index 289d8668c771755d20366c6369fd33209712f3db..bbd90a6cdddcbdf9a944dcb9c7622e099855f511 100644 --- a/DDG4/src/Geant4SteppingAction.cpp +++ b/DDG4/src/Geant4SteppingAction.cpp @@ -15,11 +15,20 @@ // Framework include files #include "DD4hep/InstanceCount.h" #include "DDG4/Geant4SteppingAction.h" +// Geant4 headers +#include "G4Threading.hh" +#include "G4AutoLock.hh" +// C/C++ include files +#include <stdexcept> +using namespace std; using namespace DD4hep::Simulation; +namespace { + G4Mutex action_mutex=G4MUTEX_INITIALIZER; +} /// Standard constructor -Geant4SteppingAction::Geant4SteppingAction(Geant4Context* ctxt, const std::string& nam) +Geant4SteppingAction::Geant4SteppingAction(Geant4Context* ctxt, const string& nam) : Geant4Action(ctxt, nam) { InstanceCount::increment(this); } @@ -34,7 +43,45 @@ void Geant4SteppingAction::operator()(const G4Step*, G4SteppingManager*) { } /// Standard constructor -Geant4SteppingActionSequence::Geant4SteppingActionSequence(Geant4Context* ctxt, const std::string& nam) +Geant4SharedSteppingAction::Geant4SharedSteppingAction(Geant4Context* ctxt, const string& nam) + : Geant4SteppingAction(ctxt, nam) +{ + InstanceCount::increment(this); +} + +/// Default destructor +Geant4SharedSteppingAction::~Geant4SharedSteppingAction() { + releasePtr(m_action); + InstanceCount::decrement(this); +} + +/// Underlying object to be used during the execution of this thread +void Geant4SharedSteppingAction::use(Geant4SteppingAction* action) { + if (action) { + action->addRef(); + m_action = action; + return; + } + throw runtime_error("Geant4SharedSteppingAction: Attempt to use invalid actor!"); +} + +/// Set or update client for the use in a new thread fiber +void Geant4SharedSteppingAction::configureFiber(Geant4Context* thread_context) { + m_action->configureFiber(thread_context); +} + +/// User stepping callback +void Geant4SharedSteppingAction::operator()(const G4Step* s, G4SteppingManager* m) { + if ( m_action ) { + G4AutoLock protection_lock(&action_mutex); { + ContextSwap swap(m_action,context()); + (*m_action)(s,m); + } + } +} + +/// Standard constructor +Geant4SteppingActionSequence::Geant4SteppingActionSequence(Geant4Context* ctxt, const string& nam) : Geant4Action(ctxt, nam) { m_needsControl = true; InstanceCount::increment(this); @@ -48,20 +95,35 @@ Geant4SteppingActionSequence::~Geant4SteppingActionSequence() { InstanceCount::decrement(this); } +/// Set or update client for the use in a new thread fiber +void Geant4SteppingActionSequence::configureFiber(Geant4Context* thread_context) { + m_actors(&Geant4Action::configureFiber, thread_context); +} + +/// Set or update client context +void Geant4SteppingActionSequence::updateContext(Geant4Context* ctxt) { + m_context = ctxt; + m_actors.updateContext(ctxt); +} + +/// Get an action by name +Geant4SteppingAction* Geant4SteppingActionSequence::get(const string& nam) const { + return m_actors.get(FindByName(TypeName::split(nam).second)); +} + /// Pre-track action callback void Geant4SteppingActionSequence::operator()(const G4Step* step, G4SteppingManager* mgr) { - m_actors(ContextUpdate(context())); m_actors(&Geant4SteppingAction::operator(), step, mgr); m_calls(step, mgr); - m_actors(ContextUpdate()); } /// Add an actor responding to all callbacks. Sequence takes ownership. void Geant4SteppingActionSequence::adopt(Geant4SteppingAction* action) { if (action) { + G4AutoLock protection_lock(&action_mutex); action->addRef(); m_actors.add(action); return; } - throw std::runtime_error("Geant4SteppingActionSequence: Attempt to add invalid actor!"); + throw runtime_error("Geant4SteppingActionSequence: Attempt to add invalid actor!"); } diff --git a/DDG4/src/Geant4TrackingAction.cpp b/DDG4/src/Geant4TrackingAction.cpp index 72767b02884a57b13e1aeffe3fc52f47bc464ce1..2eeded64129a3f54cd97a55cf0301448139e4ad8 100644 --- a/DDG4/src/Geant4TrackingAction.cpp +++ b/DDG4/src/Geant4TrackingAction.cpp @@ -20,6 +20,8 @@ // Geant4 include files #include "G4Track.hh" +#include "G4Threading.hh" +#include "G4AutoLock.hh" #include "G4TrackingManager.hh" #include "G4VUserTrackInformation.hh" @@ -31,9 +33,12 @@ using namespace DD4hep; using namespace DD4hep::Simulation; class G4Step; class G4TouchableHistory; +namespace { + G4Mutex action_mutex=G4MUTEX_INITIALIZER; +} /// Standard constructor -Geant4TrackingActionSequence::Geant4TrackingActionSequence(Geant4Context* ctxt, const std::string& nam) +Geant4TrackingActionSequence::Geant4TrackingActionSequence(Geant4Context* ctxt, const string& nam) : Geant4Action(ctxt, nam) { m_needsControl = true; InstanceCount::increment(this); @@ -50,19 +55,35 @@ Geant4TrackingActionSequence::~Geant4TrackingActionSequence() { InstanceCount::decrement(this); } +/// Set or update client context +void Geant4TrackingActionSequence::updateContext(Geant4Context* ctxt) { + m_context = ctxt; + m_actors.updateContext(ctxt); +} + +/// Set or update client for the use in a new thread fiber +void Geant4TrackingActionSequence::configureFiber(Geant4Context* thread_context) { + m_actors(&Geant4Action::configureFiber, thread_context); +} + +/// Get an action by name +Geant4TrackingAction* Geant4TrackingActionSequence::get(const string& nam) const { + return m_actors.get(FindByName(TypeName::split(nam).second)); +} + /// Add an actor responding to all callbacks. Sequence takes ownership. void Geant4TrackingActionSequence::adopt(Geant4TrackingAction* action) { if (action) { + G4AutoLock protection_lock(&action_mutex); action->addRef(); m_actors.add(action); return; } - throw std::runtime_error("Geant4TrackingActionSequence: Attempt to add invalid actor!"); + throw runtime_error("Geant4TrackingActionSequence: Attempt to add invalid actor!"); } /// Pre-track action callback void Geant4TrackingActionSequence::begin(const G4Track* track) { - m_actors(ContextUpdate(context())); m_front(track); m_actors(&Geant4TrackingAction::begin, track); m_begin(track); @@ -73,11 +94,10 @@ void Geant4TrackingActionSequence::end(const G4Track* track) { m_end(track); m_actors(&Geant4TrackingAction::end, track); m_final(track); - m_actors(ContextUpdate(0)); } /// Standard constructor -Geant4TrackingAction::Geant4TrackingAction(Geant4Context* ctxt, const std::string& nam) +Geant4TrackingAction::Geant4TrackingAction(Geant4Context* ctxt, const string& nam) : Geant4Action(ctxt, nam) { InstanceCount::increment(this); } @@ -101,49 +121,50 @@ void Geant4TrackingAction::mark(const G4Track* track) const { if ( truth ) truth->mark(track,true); } -/// Get the valid Geant4 tarck information -Geant4TrackInformation* Geant4TrackingAction::trackInfo(G4Track* track) const { - if (track) { - Geant4TrackInformation* gau = 0; - G4VUserTrackInformation* g4 = track->GetUserInformation(); - if (0 == g4) { - gau = new Geant4TrackInformation(); - track->SetUserInformation(gau); - return gau; // RETURN - } - gau = fast_cast<Geant4TrackInformation*>(g4); - if (!gau) { - error("trackInfo: invalid cast to Geant4TrajckInformation"); - } - return gau; +/// Standard constructor +Geant4SharedTrackingAction::Geant4SharedTrackingAction(Geant4Context* ctxt, const string& nam) + : Geant4TrackingAction(ctxt, nam) +{ + InstanceCount::increment(this); +} + +/// Default destructor +Geant4SharedTrackingAction::~Geant4SharedTrackingAction() { + releasePtr(m_action); + InstanceCount::decrement(this); +} + +/// Set or update client for the use in a new thread fiber +void Geant4SharedTrackingAction::configureFiber(Geant4Context* thread_context) { + m_action->configureFiber(thread_context); +} + +/// Underlying object to be used during the execution of this thread +void Geant4SharedTrackingAction::use(Geant4TrackingAction* action) { + if (action) { + action->addRef(); + m_action = action; + return; } - error("trackInfo: [Invalid G4Track]"); - return 0; -} - -/// Mark all children of the track to be stored -bool Geant4TrackingAction::storeChildren() const { - G4TrackVector* v = trackMgr()->GimmeSecondaries(); - if (v) { // loop over all children - for (G4TrackVector::const_iterator i = v->begin(); i != v->end(); ++i) { - G4Track* t = *i; - if (t) { - storeChild(trackInfo(t)); - } + throw runtime_error("Geant4SharedTrackingAction: Attempt to use invalid actor!"); +} + +/// Begin-of-track callback +void Geant4SharedTrackingAction::begin(const G4Track* track) { + if ( m_action ) { + G4AutoLock protection_lock(&action_mutex); { + ContextSwap swap(m_action,context()); + m_action->begin(track); } - return true; } - return false; } -/// Mark a single child of the track to be stored -bool Geant4TrackingAction::storeChild(Geant4TrackInformation* track_info) const { - if (0 != track_info) { - if (!track_info->storeTrack()) { - track_info->storeTrack(true); +/// End-of-track callback +void Geant4SharedTrackingAction::end(const G4Track* track) { + if ( m_action ) { + G4AutoLock protection_lock(&action_mutex); { + ContextSwap swap(m_action,context()); + m_action->end(track); } - return true; } - error("storeChild: Geant4TrackInformation points to NULL!"); - return false; } diff --git a/DDG4/src/Geant4UserInitialization.cpp b/DDG4/src/Geant4UserInitialization.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d86a8140d0a6dd86a717f18bbb804cf2d95111c6 --- /dev/null +++ b/DDG4/src/Geant4UserInitialization.cpp @@ -0,0 +1,88 @@ +// $Id$ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// Author : M.Frank +// +//========================================================================== + +// Framework include files +#include "DD4hep/InstanceCount.h" +#include "DDG4/Geant4UserInitialization.h" + +// C/C++ include files +#include <stdexcept> + +using namespace std; +using namespace DD4hep::Simulation; + +/// Standard constructor +Geant4UserInitialization::Geant4UserInitialization(Geant4Context* ctxt, const string& nam) + : Geant4Action(ctxt, nam) { + m_needsControl = false; + InstanceCount::increment(this); +} + +/// Default destructor +Geant4UserInitialization::~Geant4UserInitialization() { + InstanceCount::decrement(this); +} + +/// Callback function to build setup for the MT worker thread +void Geant4UserInitialization::build() const { +} + +/// Callback function to build setup for the MT master thread +void Geant4UserInitialization::buildMaster() const { +} + +/// Standard constructor +Geant4UserInitializationSequence::Geant4UserInitializationSequence(Geant4Context* ctxt, const string& nam) + : Geant4UserInitialization(ctxt, nam) { + m_needsControl = false; + InstanceCount::increment(this); +} + +/// Default destructor +Geant4UserInitializationSequence::~Geant4UserInitializationSequence() { + InstanceCount::decrement(this); + m_workerCalls.clear(); + m_masterCalls.clear(); + m_actors(&Geant4Action::release); + m_actors.clear(); +} + +/// Add an actor responding to all callbacks. Sequence takes ownership. +void Geant4UserInitializationSequence::adopt(Geant4UserInitialization* action) { + if (action) { + action->addRef(); + m_actors.add(action); + return; + } + throw runtime_error("Geant4UserInitializationSequence: Attempt to add invalid actor!"); +} + +/// Callback function to build setup for the MT worker thread +void Geant4UserInitializationSequence::build() const { + m_actors(&Geant4UserInitialization::build); + m_workerCalls(); +} + +/// Callback function to build setup for the MT master thread +void Geant4UserInitializationSequence::buildMaster() const { + m_actors(&Geant4UserInitialization::buildMaster); + m_masterCalls(); +} + +/// Set client context +void Geant4UserInitializationSequence::updateContext(Geant4Context* ctxt) { + m_context = ctxt; + m_actors.updateContext(ctxt); +} + diff --git a/DDG4/src/python/DDG4Python.C b/DDG4/src/python/DDG4Python.C new file mode 100644 index 0000000000000000000000000000000000000000..6e9c95087822795610e47c73d4bbc339f81c89bf --- /dev/null +++ b/DDG4/src/python/DDG4Python.C @@ -0,0 +1,36 @@ +// $Id$ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +//==================================================================== +// +// Define the ROOT dictionaries for all data classes to be saved +// which are created by the DDG4 examples. +// +// Author : M.Frank +// +//==================================================================== +// FRamework include files +#include "DDG4Python/Geant4PythonCall.h" +#include "DDG4Python/Geant4PythonAction.h" +#include "DDG4Python/Geant4PythonInitialization.h" +#include "DDG4Python/Geant4PythonDetectorConstruction.h" +#include "PyDDG4.h" + + +// CINT configuration +#if defined(__MAKECINT__) +#pragma link C++ namespace DD4hep; +#pragma link C++ namespace DD4hep::Simulation; +#pragma link C++ class DD4hep::Simulation::Geant4PythonCall; +#pragma link C++ class DD4hep::Simulation::Geant4PythonAction; +#pragma link C++ class DD4hep::Simulation::Geant4PythonInitialization; +#pragma link C++ class DD4hep::Simulation::Geant4PythonDetectorConstruction; +#pragma link C++ class PyDDG4; +#endif diff --git a/DDG4/src/python/Geant4PythonAction.cpp b/DDG4/src/python/Geant4PythonAction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..448b398a2c47edc90528cb93e360a6bed25ff1a9 --- /dev/null +++ b/DDG4/src/python/Geant4PythonAction.cpp @@ -0,0 +1,62 @@ +// Framework include files +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ + +// Framework include files +#include "DDG4/Factories.h" +#include "DDG4Python/Geant4PythonAction.h" +#include "DDG4Python/Geant4PythonCall.h" +#include "DDG4Python/DDPython.h" + +// C/C++ include files +#include <stdexcept> +#include <fstream> + +using namespace std; +using namespace DD4hep; +using namespace DD4hep::Simulation; + +DECLARE_GEANT4ACTION(Geant4PythonAction) + +/// Standard constructor, initializes variables +Geant4PythonAction::Geant4PythonAction(Geant4Context* ctxt, const string& nam) + : Geant4Action(ctxt,nam) +{ + m_needsControl = true; +} + +/// Execute command in the python interpreter. Directly forwarded to TPython. +int Geant4PythonAction::exec(const std::string& cmd) { + return DDPython::instance().execute(cmd); +} + +/// Execute command in the python interpreter. +int Geant4PythonAction::eval(const std::string& cmd) { + return DDPython::instance().evaluate(cmd); +} + +/// Execute command in the python interpreter. +int Geant4PythonAction::runFile(const std::string& cmd) { + return DDPython::instance().runFile(cmd); +} + +/// Execute command in the python interpreter. +int Geant4PythonAction::call(PyObject* method, PyObject* args) { + return Geant4PythonCall().execute<int>(method,args); +} + +/// Invoke command prompt +void Geant4PythonAction::prompt() { + DDPython::instance().prompt(); +} diff --git a/DDG4/src/python/Geant4PythonCall.cpp b/DDG4/src/python/Geant4PythonCall.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a580f40c6f57edbea226b4f8c349d45e439cdf62 --- /dev/null +++ b/DDG4/src/python/Geant4PythonCall.cpp @@ -0,0 +1,95 @@ +// Framework include files +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ + +// Framework include files +#include "DDG4Python/Geant4PythonCall.h" +#include "DDG4Python/DDPython.h" + +// C/C++ include files +#include <stdexcept> +#include "Python.h" + +using namespace std; +using namespace DD4hep; +using namespace DD4hep::Simulation; + +/// Standard constructor, initializes variables +Geant4PythonCall::Geant4PythonCall() + : m_callable(0), m_arguments(0) +{ + DDPython::instance(); +} + +Geant4PythonCall::~Geant4PythonCall() { + DDPython::GILState state(0); + DDPython::releaseObject(m_callable); + DDPython::releaseObject(m_arguments); +} + +/// Set the callback structures for callbacks with arguments +void Geant4PythonCall::set(PyObject* callable, PyObject* arguments) { + DDPython::GILState state(0); + DDPython::assignObject(m_callable,callable); + DDPython::assignObject(m_arguments,arguments); +} + +/// Set the callback structures for callbacks without arguments +void Geant4PythonCall::set(PyObject* callable) { + DDPython::GILState state(0); + DDPython::assignObject(m_callable,callable); + DDPython::assignObject(m_arguments,0); +} + +namespace DD4hep { namespace Simulation { + + /// Execute command in the python interpreter. + template <typename RETURN> RETURN Geant4PythonCall::execute() const { + DDPython::GILState state(0); + TPyReturn ret(DDPython::instance().callC(m_callable, m_arguments)); + return (RETURN)ret; + } + + /// Execute command in the python interpreter. + template <typename RETURN> RETURN Geant4PythonCall::execute(PyObject* method) const { + DDPython::GILState state(0); + TPyReturn ret(DDPython::instance().callC(method,0)); + return (RETURN)ret; + } + + /// Execute command in the python interpreter. + template <typename RETURN> RETURN Geant4PythonCall::execute(PyObject* method, PyObject* args) const { + DDPython::GILState state(0); + TPyReturn ret(DDPython::instance().callC(method,args)); + return (RETURN)ret; + } +#define INSTANTIATE(X) \ + template X Geant4PythonCall::execute<X>() const; \ + template X Geant4PythonCall::execute<X>(PyObject* method) const; \ + template X Geant4PythonCall::execute<X>(PyObject* method, PyObject* args) const + + INSTANTIATE(char); + INSTANTIATE(short); + INSTANTIATE(int); + INSTANTIATE(long); + INSTANTIATE(unsigned short); + INSTANTIATE(unsigned int); + INSTANTIATE(unsigned long); + INSTANTIATE(float); + INSTANTIATE(double); + INSTANTIATE(char*); + INSTANTIATE(const char*); + INSTANTIATE(PyObject*); + INSTANTIATE(void*); + }} diff --git a/DDG4/src/python/Geant4PythonDetectorConstruction.cpp b/DDG4/src/python/Geant4PythonDetectorConstruction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..968f393a41706791b93d7a0f92e189e48e93db05 --- /dev/null +++ b/DDG4/src/python/Geant4PythonDetectorConstruction.cpp @@ -0,0 +1,82 @@ +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ + +// Framework include files +#include "DDG4/Geant4Context.h" +#include "DDG4/Geant4Kernel.h" + +#include "DDG4Python/DDPython.h" +#include "DDG4Python/Geant4PythonAction.h" +#include "DDG4Python/Geant4PythonDetectorConstruction.h" + +using namespace std; +using namespace DD4hep::Simulation; + +#include "DDG4/Factories.h" +DECLARE_GEANT4ACTION(Geant4PythonDetectorConstruction) + +/// Standard constructor, initializes variables +Geant4PythonDetectorConstruction::Geant4PythonDetectorConstruction(Geant4Context* ctxt, const string& nam) +: Geant4DetectorConstruction(ctxt,nam), + m_constructSD(), m_constructFLD(), m_constructGEO() +{ + m_needsControl = true; +} + +/// Set the Detector initialization command +void Geant4PythonDetectorConstruction::setConstructGeo(PyObject* callable, PyObject* args) { + m_constructGEO.set(callable, args); +} + +/// Set the field initialization command +void Geant4PythonDetectorConstruction::setConstructField(PyObject* callable, PyObject* args) { + m_constructFLD.set(callable, args); +} + +/// Set the sensitive detector initialization command +void Geant4PythonDetectorConstruction::setConstructSensitives(PyObject* callable, PyObject* args) { + m_constructSD.set(callable, args); +} + +/// Execute command in the python interpreter +void Geant4PythonDetectorConstruction::exec(const string& desc, const Geant4PythonCall& cmd) const { + if ( cmd.isValid() ) { + int ret = cmd.execute<int>(); + if ( ret != 1 ) { + except("+++ %s returned %d, not SUCCESS (1). Terminating setup",desc.c_str(), ret); + } + } +} + +/// Callback function to build setup for the MT worker thread +void Geant4PythonDetectorConstruction::constructGeo(Geant4DetectorConstructionContext* ) { + info("+++ Worker:%ld Execute PYTHON constructGeo %s....", + context()->kernel().id(), m_constructGEO.isValid() ? "" : "[empty]"); + DDPython::BlockThreads blocker(0); + exec("constructGeo", m_constructGEO); +} + +/// Callback function to build setup for the MT master thread +void Geant4PythonDetectorConstruction::constructField(Geant4DetectorConstructionContext* ) { + info("+++ Worker:%ld Execute PYTHON constructField %s....", + context()->kernel().id(), m_constructFLD.isValid() ? "" : "[empty]"); + exec("constructField", m_constructFLD); +} + +/// Callback function to build setup for the MT master thread +void Geant4PythonDetectorConstruction::constructSensitives(Geant4DetectorConstructionContext* ) { + info("+++ Worker:%ld Execute PYTHON constructSensitives %s....", + context()->kernel().id(), m_constructSD.isValid() ? "" : "[empty]"); + exec("constructSensitives", m_constructSD); +} diff --git a/DDG4/src/python/Geant4PythonDetectorConstructionLast.cpp b/DDG4/src/python/Geant4PythonDetectorConstructionLast.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee70a6194b27ef41d9a46f3e04fda61913a6c317 --- /dev/null +++ b/DDG4/src/python/Geant4PythonDetectorConstructionLast.cpp @@ -0,0 +1,56 @@ +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ +#ifndef DD4HEP_DDG4_GEANT4PYTHONDETECTORCONSTRUCTIONLAST_H +#define DD4HEP_DDG4_GEANT4PYTHONDETECTORCONSTRUCTIONLAST_H + +// Framework include files +#include "DDG4/Geant4DetectorConstruction.h" +#include "DDG4Python/DDPython.h" + +/// Namespace for the AIDA detector description toolkit +namespace DD4hep { + + /// Namespace for the Geant4 based simulation part of the AIDA detector description toolkit + namespace Simulation { + + /// Base class to initialize a multi-threaded or single threaded Geant4 application + /** + * All python callbacks are supposed to return the integer '1' on success. + * Any other return code is assumed to be failure. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ + class Geant4PythonDetectorConstructionLast : public Geant4DetectorConstruction { + public: + /// Standard constructor + Geant4PythonDetectorConstructionLast(Geant4Context* ctxt, const std::string& nam) + : Geant4DetectorConstruction(ctxt,nam) {} + /// Default destructor + virtual ~Geant4PythonDetectorConstructionLast() {} + /// Geometry construction callback. Called at "Construct()" + virtual void constructGeo(Geant4DetectorConstructionContext*) { + info("+++ Python setup finished. From now on THREADS ARE ALLOWED!"); + DDPython::allowThreads(); + } + }; + } // End namespace Simulation +} // End namespace DD4hep +#endif // DD4HEP_DDG4_GEANT4PYTHONDETECTORCONSTRUCTIONLAST_H + +using namespace DD4hep::Simulation; + +#include "DDG4/Factories.h" +DECLARE_GEANT4ACTION(Geant4PythonDetectorConstructionLast) diff --git a/DDG4/src/python/Geant4PythonInitialization.cpp b/DDG4/src/python/Geant4PythonInitialization.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1558eeead37dad9390bfb182b31f8a940ee39558 --- /dev/null +++ b/DDG4/src/python/Geant4PythonInitialization.cpp @@ -0,0 +1,66 @@ +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ + +// Framework include files +#include "DDG4/Factories.h" +#include "DDG4/Geant4Kernel.h" +#include "DDG4Python/DDPython.h" +#include "DDG4Python/Geant4PythonInitialization.h" + +using namespace std; +using namespace DD4hep::Simulation; + +DECLARE_GEANT4ACTION(Geant4PythonInitialization) + +/// Standard constructor, initializes variables +Geant4PythonInitialization::Geant4PythonInitialization(Geant4Context* ctxt, const string& nam) +: Geant4UserInitialization(ctxt,nam), m_masterSetup(), m_workerSetup() +{ + m_needsControl = true; +} + +/// Set the Detector initialization command +void Geant4PythonInitialization::setMasterSetup(PyObject* callable, PyObject* args) { + m_masterSetup.set(callable, args); +} + +/// Set the field initialization command +void Geant4PythonInitialization::setWorkerSetup(PyObject* callable, PyObject* args) { + m_workerSetup.set(callable, args); +} + +/// Execute command in the python interpreter +void Geant4PythonInitialization::exec(const string& desc, const Geant4PythonCall& cmd) const { + if ( cmd.isValid() ) { + int ret = cmd.execute<int>(); + if ( ret != 1 ) { + except("+++ %s returned %d, not SUCCESS (1). Terminating setup",desc.c_str(), ret); + } + } +} + +/// Callback function to build setup for the MT worker thread +void Geant4PythonInitialization::build() const { + info("+++ Worker:%ld Build PYTHON Worker %s....", + context()->kernel().id(), m_workerSetup.isValid() ? "[empty]" : ""); + exec("Worker setup command",m_workerSetup); +} + +/// Callback function to build setup for the MT master thread +void Geant4PythonInitialization::buildMaster() const { + DDPython::BlockThreads blocker(0); + info("+++ Build PYTHON Master [id:%ld] %s ....", + context()->kernel().id(), m_masterSetup.isValid() ? "[empty]" : ""); + exec("Master setup command",m_masterSetup); +} diff --git a/DDG4/src/python/PyDDG4.cpp b/DDG4/src/python/PyDDG4.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c3e5094211f6113ca42b9505c4101e4c8a4a8cc --- /dev/null +++ b/DDG4/src/python/PyDDG4.cpp @@ -0,0 +1,45 @@ +// Framework include files +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ + +// Framework include files +#include "PyDDG4.h" +#include "DD4hep/LCDD.h" +#include "DDG4Python/DDPython.h" + +int PyDDG4::run(Kernel& kernel) { + int ret; + DD4hep::DDPython::AllowThreads allow(0); + if ( 1 != (ret=kernel.configure()) ) return ret; + if ( 1 != (ret=kernel.initialize()) ) return ret; + if ( 1 != (ret=kernel.run()) ) return ret; + if ( 1 != (ret=kernel.terminate()) ) return ret; + //DD4hep::DDPython::shutdown(); + return ret; +} + +int PyDDG4::execute() { + Kernel& k = Kernel::access(DD4hep::Geometry::LCDD::getInstance()); + return run(k); +} + +int PyDDG4::process(const char* fname) { + return DD4hep::DDPython::instance().runFile(fname); +} + +int PyDDG4::run(const char* fname) { + int ret = DD4hep::DDPython::instance().runFile(fname); + if ( 1 != ret ) return ret; + return execute(); +} diff --git a/DDG4/src/python/PyDDG4.h b/DDG4/src/python/PyDDG4.h new file mode 100644 index 0000000000000000000000000000000000000000..8f42e26af5ae147209a18bd78fc9a0a6a0bde218 --- /dev/null +++ b/DDG4/src/python/PyDDG4.h @@ -0,0 +1,30 @@ +// Framework include files +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-03 +// +//========================================================================== +// $Id$ +#ifndef DD4HEP_DDG4_PYDDG4_H +#define DD4HEP_DDG4_PYDDG4_H + +// Framework include files +#include "DDG4/Geant4Kernel.h" + +struct PyDDG4 { + typedef DD4hep::Simulation::Geant4Kernel Kernel; + + static int execute(); + static int process(const char* fname); + static int run(Kernel& kernel); + static int run(const char* fname); +}; + +#endif // DD4HEP_DDG4_PYDDG4_H diff --git a/DDG4/tpython/DDPython.C b/DDG4/tpython/DDPython.C new file mode 100644 index 0000000000000000000000000000000000000000..c6092688db4eb8fa60b152cb61e01ae2ccaa41f3 --- /dev/null +++ b/DDG4/tpython/DDPython.C @@ -0,0 +1,33 @@ +// $Id$ +//========================================================================== +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +//==================================================================== +// +// Define the ROOT dictionaries for all data classes to be saved +// which are created by the DDG4 examples. +// +// Author : M.Frank +// +//==================================================================== +// FRamework include files +#include "DDG4Python/DDPython.h" + +struct DD4hepPython { + static void setMainThread() { + DD4hep::DDPython::setMainThread(); + } +}; + +// CINT configuration +#if defined(__MAKECINT__) +#pragma link C++ namespace DD4hep; +#pragma link C++ class DD4hep::DDPython; +#pragma link C++ class DD4hepPython; +#endif diff --git a/DDG4/tpython/DDPython.cpp b/DDG4/tpython/DDPython.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64afefd5418bb948973a9d600f10a5edda699489 --- /dev/null +++ b/DDG4/tpython/DDPython.cpp @@ -0,0 +1,287 @@ +// AIDA Detector description implementation for LCD +//-------------------------------------------------------------------------- +// 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. +// +// \author Markus Frank +// \date 2015-11-07 +// +//========================================================================== +// $Id$ + +// Framework include files +#include "DDG4Python/DDPython.h" +#include "DD4hep/Printout.h" + +// C/C++ include files +#include "TPyReturn.h" +#include "Python.h" +#include <fstream> +#include <sstream> +#include <pthread.h> + +// Forward declartions + +using namespace std; +using namespace DD4hep; + +namespace { + string loadScript(const string& fname) { + ifstream file(fname.c_str()); + stringstream str; + if( file ) { + char ch; + while( file.get(ch) ) str.put(ch); + file.close(); + return str.str(); + } + return ""; + } + + static int _blockers = 0; + static pthread_t _mainThread = 0; + static int _refCount = 0; + static DDPython* _instance = 0; + static PyObject* _main_dict = 0; + static PyThreadState *_save_state = 0; + int _execPy(const char* cmd) { + DDPython::GILState state(0); + PyObject* ret = ::PyRun_String((char*)cmd, Py_file_input,_main_dict,_main_dict); + if ( ::PyErr_Occurred() ) { + ::PyErr_Print(); + ::PyErr_Clear(); + return 0; + } + if ( ret && ret == Py_None ) { + Py_DECREF( ret ); + return 1; + } + else if ( ret ) { + TPyReturn r(ret); + Py_DECREF( ret ); + return (int)r; + } + return 0; + } + int _evalPy(const char* cmd) { + DDPython::GILState state(0); + PyObject* ret = ::PyRun_String((char*)cmd, Py_eval_input,_main_dict,_main_dict); + if ( ::PyErr_Occurred() ) { + ::PyErr_Print(); + ::PyErr_Clear(); + return 0; + } + if ( ret && ret == Py_None ) { + Py_DECREF( ret ); + return 1; + } + else if ( ret ) { + TPyReturn r(ret); + Py_DECREF( ret ); + return (int)r; + } + return 0; + } +} + +DDPython::GILState::GILState(int) { + if ( ::Py_IsInitialized() ) { + PyGILState_STATE st = (PyGILState_STATE)::PyGILState_Ensure(); + state = (int)st; + } +} + +DDPython::GILState::~GILState() { + if ( ::Py_IsInitialized() ) { + PyGILState_STATE st = (PyGILState_STATE)state; + ::PyGILState_Release(st); + } +} + +DDPython::BlockThreads::BlockThreads(int) { + if ( _blockers == 0 ) { + DDPython::restoreThread(); + } + ++_blockers; +} + +DDPython::BlockThreads::~BlockThreads() { + --_blockers; + if ( _blockers == 0 ) { + DDPython::allowThreads(); + } +} + +DDPython::AllowThreads::AllowThreads(int) { + DDPython::allowThreads(); +} + +DDPython::AllowThreads::~AllowThreads() { + DDPython::restoreThread(); +} + +/// Standard constructor, initializes variables +DDPython::DDPython() { + ++_refCount; + bool inited = ::Py_IsInitialized(); + if ( !inited ) { + ::Py_Initialize(); + ::PyEval_InitThreads(); + } + else { + _refCount += 1000; // Ensure we do not call Py_Finalize()! + } + if ( !_main_dict ) { + // retrieve the main dictionary + PyObject* module = ::PyImport_AddModule("__main__"); + if ( !module || ::PyErr_Occurred() ) { + ::PyErr_Print(); + ::PyErr_Clear(); + ::printf("WARNING: main dictionary pointer is NULL. Try to continue like this!\n"); + } + else { + _main_dict = ::PyModule_GetDict(module); + if ( _main_dict ) { + Py_INCREF( _main_dict ); + } + ::printf("Pointer to main dict:%p\n",(void*)_main_dict); + } + setMainThread(); + } + //if ( !isMainThread() ) context = ::PyEval_SaveThread(); + if ( !_save_state ) { + //_save_state = ::PyEval_SaveThread(); + } +} + +/// Default Destructor +DDPython::~DDPython() { + --_refCount; + if ( 0 == _refCount && ::Py_IsInitialized() ) { + DD4hep::printout(ALWAYS,"DDPython","+++ Shutdown python interpreter......"); + if ( _main_dict ) { + Py_DECREF(_main_dict); + _main_dict = 0; + } + if ( _save_state ) { + ::PyEval_RestoreThread(_save_state); + } + ::Py_Finalize(); + _instance = 0; + } +} + + +DDPython DDPython::instance() { + if ( 0 == _instance ) _instance = new DDPython(); + return DDPython(); +} + +/// Save thread state +void DDPython::allowThreads() { + if ( !_save_state && ::Py_IsInitialized() ) { + _save_state = ::PyEval_SaveThread(); + } +} + +void DDPython::restoreThread() { + if ( _save_state ) { + ::PyEval_RestoreThread(_save_state); + _save_state = 0; + } +} + +int DDPython::setArgs(int argc, char** argv) const { + ::PySys_SetArgv(argc,argv); + return 1; +} + +void DDPython::shutdown() { + if ( 0 != _instance ) { + if ( 1 == _refCount ) { + delete _instance; + _instance = 0; + } + } +} + +int DDPython::runFile(const std::string& fname) const { + std::string cmd = loadScript(fname); + return execute(cmd); +} + +int DDPython::evaluate(const std::string& cmd) const { + return _evalPy(cmd.c_str()); +} + +int DDPython::execute(const std::string& cmd) const { + return _execPy(cmd.c_str()); +} + +PyObject* DDPython::call(PyObject* method, PyObject* args) { + DDPython::GILState state(0); + if ( PyCallable_Check(method) ) { + PyObject* ret = ::PyObject_CallObject(method,args==Py_None ? NULL : args); + return ret; + } + ::PyErr_SetString(PyExc_RuntimeError,"DDPython::call: The argument is not a callable object!"); + return 0; +} + +TPyReturn DDPython::callC(PyObject* method, PyObject* args) { + if ( PyCallable_Check(method) ) { + PyObject* arg = args==Py_None || args==0 ? 0 : args; + PyObject* ret = ::PyObject_CallObject(method,arg); + if ( ::PyErr_Occurred() ) { + ::PyErr_Print(); + ::PyErr_Clear(); + return TPyReturn(); + } + else if ( ret ) { + return TPyReturn(ret); + } + } + throw runtime_error("DDPython::callC: Object is not callable!"); +} + +/// Release python object +void DDPython::releaseObject(PyObject*& obj) { + if ( obj && ::Py_IsInitialized() ) { + Py_DECREF(obj); + } + obj = 0; +} + +/// Release python object +void DDPython::assignObject(PyObject*& obj, PyObject* new_obj) { + if ( ::Py_IsInitialized() ) { + if ( obj ) Py_DECREF(obj); + if ( new_obj ) Py_INCREF(new_obj); + } + obj = new_obj; +} + +void DDPython::prompt() const { + DDPython::GILState state(0); + ::PyRun_InteractiveLoop(stdin,const_cast<char*>("\0")); +} + +void DDPython::afterFork() const { + if ( ::Py_IsInitialized() ) { + cout << "[INFO] Re-init python after forking....." << endl; + ::PyOS_AfterFork(); + ::PyEval_InitThreads(); + ::PyEval_ReleaseLock(); + } +} + +void DDPython::setMainThread() { + _mainThread = pthread_self(); +} + +bool DDPython::isMainThread() { + return _mainThread == pthread_self(); +} diff --git a/doc/CompileAllOptionPermutations.sh b/doc/CompileAllOptionPermutations.sh index cbfd717dd4199306c43dc4720e57412bc5acdf8f..79fa66b41e60bab72a8ec407d64a1d87e7312ae1 100755 --- a/doc/CompileAllOptionPermutations.sh +++ b/doc/CompileAllOptionPermutations.sh @@ -5,8 +5,8 @@ INSTALL_G4=${SW}/g4_10.01.p02_dbg/lib/Geant4-10.1.2; INSTALL_LCIO=${SW}/lcio/v02-04-03; INSTALL_XERCESC=${SW}/xercesc; CHECKOUT=${dir_name}/../../DD4hep.trunk/checkout; -export ROOTSYS=${SW}/root_v6.04.00_dbg; export ROOTSYS=${SW}/root_v5.34.25_dbg; +export ROOTSYS=${SW}/root_v6.04.00_dbg; . ${ROOTSYS}/bin/thisroot.sh; #cat ${ROOTSYS}/bin/thisroot.sh; # @@ -46,7 +46,7 @@ make_build() echo ${CMD}; exit 1 fi - make install VERBOSE=1 -j 5; + make install VERBOSE=1 -j 4; if [ $? -ne 0 ]; then make_output "DANGER WILL ROBINSON DANGER!" "++++ Failed BUILD:" echo ${CMD}; @@ -62,10 +62,17 @@ make_build() build_all() { - for DOGEANT4 in OFF ON; do - for DOXERCESC in OFF ON; do + DEF_MODES="ON OFF"; + G4_MODES="${DEF_MODES}"; + XERCES_MODES="${DEF_MODES}"; + LCIO_MODES="${DEF_MODES}"; + #G4_MODES="ON"; + #XERCES_MODES="ON"; + #LCIO_MODES="ON"; + for DOGEANT4 in ${G4_MODES}; do + for DOXERCESC in ${XERCES_MODES}; do for DOGEAR in OFF; do - for DOLCIO in OFF ON; do + for DOLCIO in ${LCIO_MODES}; do folder=build_Xer${DOXERCESC}_Geant${DOGEANT4}_Gear${DOGEAR}_Lcio${DOLCIO} WORK_DIR=${dir_name}/${folder}; mkdir -p ${WORK_DIR}/EX; @@ -76,6 +83,7 @@ build_all() OPTS="`make_opt ${DOGEANT4} -DDD4HEP_USE_GEANT4 -DGeant4_DIR=${INSTALL_G4}`\ `make_opt ${DOLCIO} -DDD4HEP_USE_LCIO -DLCIO_DIR=${INSTALL_LCIO}` \ `make_opt ${DOXERCESC} -DDD4HEP_USE_XERCESC -DXERCESC_ROOT_DIR=${INSTALL_XERCESC}` \ + -DDD4HEP_NO_REFLEX=ON -DDD4HEP_USE_CXX11=ON \ -DROOTSYS=${ROOTSYS} -DCMAKE_INSTALL_PREFIX=${WORK_DIR}/DD4hep"; CMD="cd ${dir_name}/$folder ; cmake ${OPTS} ${CHECKOUT};"; make_build; @@ -86,6 +94,7 @@ build_all() OPTS_ex="`make_opt ${DOGEANT4} -DDD4HEP_USE_GEANT4 -DGeant4_DIR=${INSTALL_G4}`\ `make_opt ${DOLCIO} -DDD4HEP_USE_LCIO -DLCIO_DIR=${INSTALL_LCIO}` \ `make_opt ${DOXERCESC} -DDD4HEP_USE_XERCESC -DXERCESC_ROOT_DIR=${INSTALL_XERCESC}` \ + -DDD4HEP_NO_REFLEX=ON -DDD4HEP_USE_CXX11=ON \ -DROOTSYS=${ROOTSYS}"; source ${DD4hep_DIR}/bin/thisdd4hep.sh; CMD="cd ${WORK_DIR}/EX; cmake ${OPTS} -DDD4hep_DIR=${DD4hep_DIR} ${CHECKOUT}/examples;"; diff --git a/doc/DDG4Manual.pdf b/doc/DDG4Manual.pdf index b1092bae184bd0aedd3ee8b3119553fae0953d26..f58fdb3aae2f13f06fa735ed98541c17f04ace50 100644 Binary files a/doc/DDG4Manual.pdf and b/doc/DDG4Manual.pdf differ diff --git a/doc/LaTex/DDG4-Detector-Construction.png b/doc/LaTex/DDG4-Detector-Construction.png new file mode 100644 index 0000000000000000000000000000000000000000..57106ca0d0a598f7719a6b1bebc659e3f430084d Binary files /dev/null and b/doc/LaTex/DDG4-Detector-Construction.png differ diff --git a/doc/LaTex/DDG4-User-Initialization.png b/doc/LaTex/DDG4-User-Initialization.png new file mode 100644 index 0000000000000000000000000000000000000000..ed26ba893124a6379140f59592bd61163aaaa0a9 Binary files /dev/null and b/doc/LaTex/DDG4-User-Initialization.png differ diff --git a/doc/LaTex/DDG4Manual-Components.tex b/doc/LaTex/DDG4Manual-Components.tex new file mode 100644 index 0000000000000000000000000000000000000000..3fcbd78da16d6df99e8e4091375b2e4e3e31ec96 --- /dev/null +++ b/doc/LaTex/DDG4Manual-Components.tex @@ -0,0 +1,703 @@ + +%============================================================================= +\section{Existing DDG4 components} +\label{sec:existing-ddg4-components} +%============================================================================= +\noindent +In the introduction the longterm goal was expressed, that with DDG4 users +should be able to pick components from a growing palette and connect the +selected components using the setup mechanisms described in +Section~\ref{sec:ddg4-implementation-setup}. + +\noindent +Such a palette based approach obviously depends on the availability of +documentation for existing components describing the properties +of each component and the interaction of each component within the \DDG +framework. + +\noindent +All components defer from the basic type \tts{Geant4Action}. This means +\bold{all} components have the \bold{default} properties described in the +table below: + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l l p{9cm} } +\hline +Component Properties: & & \tts{default} \\ +\hline +\bold{OuputLevel} & [int] & Output level of the component to customize printouts \\ +\bold{Name} & [string] & Component name [read-only] \\ +\bold{Control} & [boolean] & Steering of the Geant4 Messenger creation \\ +\hline +\end{tabular} + + +\vspace{5cm} + +\begin{center} +{\large{\bf{ +\begin{tabular} {| p{15cm} |} +\hline\space \\ + +\noindent +{\underline{Important notice for developers:}} \\ + +\noindent +Since the documentation of developed components is VERY important, +please never forget to supply the corresponding documentation.\\ +\\ +\noindent +At least supply the minimal documentation ash shown below +in the appended examples for the "Simple" detector response and I/O +components. +\\ \space\hline +\end{tabular} +}}} +\end{center} +\clearpage + +%============================================================================= +\subsection{Generic Action Modules} +%============================================================================= + +%============================================================================= +\subsubsection{Geant4UIManager} +%============================================================================= +\noindent +The {\tt{Geant4UIManager}} handles interactivity aspects between Geant4, +its command handlers (i.e. terminal) and the various components the actions +interact. + +\noindent +The {\tt{Geant4UIManager}} is a component attached to the {\tt{Geant4Kernel}} +object. All properties of all {\tt{Geant4Action}} instances may be exported to +\tts{Geant4} messengers and {\em{may}} hence be accessible directly from +the \tts{Geant4} prompt. To export properties from any action, call the +{\tt{enableUI()}} method of the action. +\noindent +The callback signature is: \tts{void operator()(G4Event* event)}. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4UIManager} \\ +\bold{File name} & \tts{DDG4/src/Geant4UIManager.cpp} \\ +\bold{Type} & \tts{Geant4Action} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\hline +\bold{SessionType} (string) & Session type (csh, tcsh, etc. \\ +\bold{SetupUI} (string) & Name of the UI macro file \\ +\bold{SetupVIS} (string) & Name of the visualization macro file \\ +\bold{HaveVIS} (bool) & Flag to instantiate Vis manager + (def:false, unless VisSetup set) \\ +\bold{HaveUI} (bool) & Flag to instantiate UI (default=true) \\ +\end{tabular} + +%============================================================================= +\subsubsection{Geant4Random} +%============================================================================= +\noindent +Mini interface to the random generator of the application. +Necessary, that on every object creates its own instance, but accesses +the main instance available through the \tts{Geant4Context}. + +\noindent +This is mandatory to ensure reproducibility of the event generation +process. Particular objects may use a dependent generator from +an experiment framework like \tts{GAUDI}. + +\noindent +internally the engine factory mechanism of \tts{CLHEP} is used. Please refer +there within for valid engine names and the random seeding mechanism, +which may vary between different engines. + +\noindent +Any number of independent random objects may be created and used +in parallel. This however, is not advised to ensure reproducibility. + +\noindent +The first instance of the random action is automatically set +to be the \tts{Geant4} instance. If another instance should be used by +\tts{Geant4}, use \tts{setMainInstance(Geant4Random* ptr)} class method to +override this behavior. +Provision, steered by options, is taken to ensure the \tts{gRandom} +of \tts{ROOT} uses the same random number engine. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4Random} \\ +\bold{File name} & \tts{DDG4/src/Geant4Random.cpp} \\ +\bold{Type} & \tts{Geant4Random} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\hline +\bold{File} (string) & File name if initialized from file. \\ + & If set, engine name and seeds are ignored \\ +\bold{Engine} (string) & Engine type name. \\ + & All engines defined in the + \tts{CLHEP::EngineFactory} class are available. + If no type is supplied the engine from the + HepRandom generator instance is taken. \\ +\bold{Seed} (long) & Initial random seed. \\ + & Default: 123456789. \\ + & If not ZERO terminated, termination is added. \\ +\bold{Replace\_gRandom} (bool) & Flag to replace the \tts{ROOT} \tts{gRandom} + instance with this random number engine. + This ensures \tts{ROOT} and \tts{Geant4} + use the same random number engine, hence + the same random sequence. + \\ +\end{tabular} + +\noindent +%============================================================================= +\subsection{Geant4UserInitialization Implementations} +%============================================================================= +\noindent +%============================================================================= +\subsubsection{Geant4PythonInitialization} +%============================================================================= +\noindent +Please see Section~\ref{sec:ddg4-multi-threading-python} +for an illustration of the usage. +The configuration by construction must be performed using setter-functions +rather than properties. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4PythonInitialization} \\ +\bold{File name} & \tts{DDG4/src/python/Geant4PythonInitialization.cpp} \\ +\bold{Type} & \tts{Geant4Action} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\end{tabular} + +%============================================================================= +\subsubsection{Geant4PythonDetectorConstruction} +%============================================================================= +\noindent +Please see Section~\ref{sec:ddg4-multi-threading-python} +for an illustration of the usage. +The configuration by construction must be performed using setter-functions +rather than properties. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4PythonDetectorConstruction} \\ +\bold{File name} & \tts{DDG4/src/python/Geant4PythonDetectorConstruction.cpp} \\ +\bold{Type} & \tts{Geant4Action} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\end{tabular} + +%============================================================================= +\subsection{Predefined Geant4 Physics List Objects} +%============================================================================= +\noindent +The physics list may be defined entirely data driven using the factory mechanism +using a variety of predefined objects. Though users are free to define private +physics lists, typically the predefined physics lists from \tts{Geant4} are used. + +\noindent +The inventory changes over time, new lists appear and obsolete lists are purged, +hence we will not list them explicitly here. +For the inventory of available physics lists, please refer to the implementation files: + +\noindent +\begin{itemize}\itemcompact +\item Inventory of predefined physics lists, which may be inherited:\\ +\detdesc{html/_geant4_physics_lists_8cpp_source.html} +{DDG4/plugins/Geant4PhysiscsLists.cpp} +\item Inventory of predefined physics constructors, which may be instantiated:\\ +\detdesc{html/_geant4_physics_constructors_8cpp_source.html} +{DDG4/plugins/Geant4PhysicsConstructors.cpp} +\item Inventory of predefined process constructors, which may be instantiated:\\ +\detdesc{html/_geant4_processes_8cpp_source.html} +{DDG4/plugins/Geant4Processes.cpp} +\item Inventory of predefined particle constructors, which may be instantiated:\\ +\detdesc{html/_geant4_particles_8cpp_source.html} +{DDG4/plugins/Geant4Particles.cpp} +\end{itemize} +\newpage + +%============================================================================= +\subsection{Geant4 Generation Action Modules} +%============================================================================= +\noindent +Here we discuss modules, which are intrinsically part of DDG4 and may be +attached to the {\tt{Geant4GeneratorActionSequence}}. + +%============================================================================= +\subsubsection{Base class: Geant4GeneratorAction} +%============================================================================= +\noindent +The \tts{Geant4GeneratorAction} is called for every event. +During the callback all particles are created which form the +microscopic kinematic action of the particle collision. +This input may either origin directly from an event generator program +or come from file. + +\noindent +The callback signature is: void operator()(G4Event* event) +\noindent +See also: +\detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_generator_action.html} +{\tts{Geant4EventAction}} in the doxygen documentation. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4GeneratorAction} \\ +\bold{File name} & \tts{DDG4/src/Geant4GeneratorAction.cpp} \\ +\bold{Type} & \tts{Geant4Action, Geant4GeneratorAction} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\hline +\end{tabular} + +%============================================================================= +\subsubsection{Geant4GeneratorActionSequence} +%============================================================================= +\noindent +The sequence dispatches the callbacks at the beginning +of an event to all registered \tts{Geant4GeneratorAction} members and all +registered callbacks. + +\noindent +See also: +\noindent +The {\tt{Geant4GeneratorActionSequence}} is directly steered by the single +instance of the {\tt{G4VUserPrimaryGeneratorAction}}, the Geant4 provided user hook, +which is private.\\ +See also: +\detdesc{html/struct_d_d4hep_1_1_simulation_1_1_geant4_user_generator_action.html} +{\tts{Geant4UserGeneratorAction}} and +\detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_generator_action_sequence.html} +{\tts{Geant4GeneratorActionSequence}} in the doxygen documentation. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4Geant4GeneratorActionSequence} \\ +\bold{File name} & \tts{DDG4/src/Geant4GeneratorAction.cpp} \\ +\bold{Type} & \tts{Geant4Action} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\hline +\end{tabular} + +%============================================================================= +\subsubsection{Geant4GeneratorActionInit} +%============================================================================= +\noindent +Initialize the Geant4Event objects to host generator and MC truth related information +Geant4 actions to collect the MC particle information. +This action should register all event extension required for the further +processing. We want to avoid that every client has to check if a given +object is present or not and than later install the required data structures. + +\noindent +These by default are extensions of type: +\begin{itemize}\itemcompact +\item \tts{Geant4PrimaryEvent} with multiple interaction sections, one for each interaction + This is the MAIN and ONLY information to feed Geant4 +\item \tts{Geant4PrimaryInteraction} containing the track/vertex information to create + the primary particles for Geant4. This record is build from the \tts{Geant4PrimaryEvent} + information. +\item \tts{Geant4PrimaryMap} a map of the \tts{Geant4Particles} converted to + \tts{G4PrimaryParticles} to ease particle handling later. +\item \tts{Geant4ParticleMap} the map of particles created during the event simulation. + This map has directly the correct particle offsets, so that the merging of + \tts{Geant4PrimaryInteraction} particles and the simulation particles is easy.... +\end{itemize} + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4Geant4GeneratorActionInit} \\ +\bold{File name} & \tts{DDG4/src/Geant4GeneratorActionInit.cpp} \\ +\bold{Type} & \tts{Geant4GeneratorAction} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\bold{Angle} (double) & \tts{Lorentz-Angle of boost} \\ +\bold{Mask} (int.bitmask) & \tts{Interaction identifier} \\ +\hline +\end{tabular} + +%============================================================================= +\subsubsection{Geant4InteractionVertexBoost} +%============================================================================= +\noindent +Boost the primary vertex and all particles outgoing the primary interaction in X-direction. + +\noindent +The interaction to be processed by the component is uniquely identified +by the {\bf{Mask}} property. Two primary interaction may not have the same +mask. + +\noindent +{\bold{Note [special use case]:}}\\ +If all contributing interactions of the one event \bold{registered +in the primary event at the time the action is called} should be handled by +one single component instance, set the {\bf{Mask}} property to {\bold{-1}}. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4InteractionVertexBoost} \\ +\bold{File name} & \tts{DDG4/src/Geant4InteractionVertexBoost.cpp} \\ +\bold{Type} & \tts{Geant4GeneratorAction} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\bold{Angle} (double) & \tts{Lorentz-Angle of boost} \\ +\bold{Mask} (int.bitmask) & \tts{Interaction identifier} \\ +\hline +\end{tabular} + +%============================================================================= +\subsubsection{Geant4InteractionVertexSmear} +%============================================================================= +\noindent +Smear the primary vertex and all particles outgoing the primary interaction. + +\noindent +The interaction to be processed by the component is uniquely identified +by the {\bf{Mask}} property. Two primary interaction may not have the same +mask. + +\noindent +{\bold{Note [special use case]:}}\\ +If all contributing interactions of the one event \bold{registered +in the primary event at the time the action is called} should be handled by +one single component instance, set the {\bf{Mask}} property to {\bold{-1}}. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4InteractionVertexSmear} \\ +\bold{File name} & \tts{DDG4/src/Geant4InteractionVertexSmear.cpp} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\bold{Offset} (PxPyPzEVector) & \tts{Smearing offset} \\ +\bold{Sigma} (PxPyPzEVector) & \tts{Sigma (Errors) on offset} \\ +\bold{Mask} (int.bitmask) & \tts{Interaction identifier} \\ +\hline +\end{tabular} + +%============================================================================= +\subsubsection{Geant4InteractionMerger} +%============================================================================= +\noindent +Merge all interactions created by each {\tt{Geant4InputAction}} into one single +record. The input records are taken from the item {\tt{Geant4PrimaryEvent}} +and are merged into the {\tt{Geant4PrimaryInteraction}} object attached to the +{\tt{Geant4Event}} event context. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4InteractionMerger} \\ +\bold{File name} & \tts{DDG4/src/Geant4InteractionMerger.cpp} \\ +\bold{Type} & \tts{Geant4GeneratorAction} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\hline +\end{tabular} + +%============================================================================= +\subsubsection{Geant4PrimaryHandler} +%============================================================================= +\noindent +Convert the primary interaction (object {\tt{Geant4PrimaryInteraction}} object +attached to the {\tt{Geant4Event}} event context) and pass the result +to Geant4 for simulation. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4PrimaryHandler} \\ +\bold{File name} & \tts{DDG4/src/Geant4PrimaryHandler.cpp} \\ +\bold{Type} & \tts{Geant4GeneratorAction} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\hline +\end{tabular} + +%============================================================================= +\subsubsection{Geant4ParticleGun} +%============================================================================= +\noindent +Implementation of a particle gun using Geant4Particles. + +\noindent +The {\tt{Geant4ParticleGun}} is a tool to shoot a number of +particles with identical properties into a given region of the +detector to be simulated. + +\noindent +The particle gun is a input source like any other and participates +in the general input stage merging process like any other input +e.g. from file. Hence, there may be several particle guns present +each generating it's own primary vertex. Use the mask property to +ensure each gun generates it's own, well identified primary vertex. + +\noindent +There is one 'user lazyness' support though: +If there is only one particle gun in use, the property 'Standalone', +which by default is set to true invokes the interaction merging and the +Geant4 primary generation directly. + +\noindent +The interaction to be created by the component is uniquely identified +by the {\bf{Mask}} property. Two primary interaction may not have the same +mask. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4PrimaryHandler} \\ +\bold{File name} & \tts{DDG4/src/Geant4PrimaryHandler.cpp} \\ +\bold{Type} & \tts{Geant4GeneratorAction} \\ +\hline +Component Properties: & default \\ +\bold{particle} (string) & Particle type to be shot \\ +\bold{energy} (double) & Particle energy in $MeV$ \\ +\bold{position} (XYZVector) & Pole position of the generated particles in $mm$\\ +\bold{direction} (XYZVector) & Momentum direction of the generated particles\\ +\bold{isotrop} (bool) & Isotropic particle directions in space. \\ +\bold{Mask} (int.bitmask) & Interaction identifier \\ +\bold{Standalone} (bool) & Setup for standalone execution \\ + & including interaction merging etc. \\ +\hline +\end{tabular} + +%============================================================================= +\subsubsection{Geant4ParticleHandler} +%============================================================================= +\noindent +Extract the relevant particle information during the simulation step. + +\noindent +This procedure works as follows: +\begin{itemize}\itemcompact +\item At the beginning of the event generation the object registers itself as + Monte-Carlo truth handler to the event context. +\item At the begin of each track action a particle candidate is created and filled + with all properties known at this time. +\item At each stepping action a flag is set if the step produced secondaries. +\item Sensitive detectors call the MC truth handler if a hit was created. + This fact is remembered. +\item At the end of the tracking action a first decision is taken if the candidate is to be + kept for the final record. +\item At the end of the event action finally all particles are reduced to the + final record. This logic can be overridden by a user handler to be attached. +\end{itemize} +\noindent +Any of these actions may be intercepted by a {\tt{Geant4UserParticleHandler}} +attached to the particle handler. +See class {\tt{Geant4UserParticleHandler}} for details. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{9cm} } +\hline +\bold{Class name} & \tts{Geant4ParticleHandler} \\ +\bold{File name} & \tts{DDG4/src/Geant4ParticleHandler.cpp} \\ +\bold{Type} & \tts{Geant4GeneratorAction} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\bold{KeepAllParticles} (bool) & Flag to keep entire particle record without any reduction. + This may result in a huge output record. \\ +\bold{SaveProcesses} (vector(string)) & Array of Geant4 process names, + which products and parent should NOT be reduced.\\ +\bold{MinimalKineticEnergy} (double) & Minimal energy below which particles should be + ignored unless other criteria + (Process, created hits, etc) apply.\\ +\hline +\end{tabular} +\newpage + +%============================================================================= +\subsection{Geant4 Event Action Modules} +%============================================================================= +\noindent + +%============================================================================= +\subsubsection{Base class: Geant4EventAction} +%============================================================================= +\noindent +The EventAction is called for every event. + +\noindent +This class is the base class for all user actions, which have +to hook into the begin- and end-of-event actions. +Typical use cases are the collection/computation of event +related properties. + +\noindent +Examples of this functionality may include for example: +\begin{itemize}\itemcompact +\item Reset variables summing event related information in the + begin-event callback. +\item Monitoring activities such as filling histograms + from hits collected during the end-event action. +\end{itemize} +See also: +\detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_event_action.html} +{\tts{Geant4EventAction}} in the doxygen documentation. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4EventAction} \\ +\bold{File name} & \tts{DDG4/src/Geant4EventAction.cpp} \\ +\bold{Type} & \tts{Geant4EventAction} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\hline +\end{tabular} + +%============================================================================= +\subsubsection{Geant4EventActionSequence} +%============================================================================= +\noindent + +\noindent +The {\tt{Geant4EventActionSequence}} is directly steered by the single +instance of the {\tt{G4UserEventAction}}, the Geant4 provided user hook, +which is private.\\ +See also: +\detdesc{html/struct_d_d4hep_1_1_simulation_1_1_geant4_user_event_action.html} +{\tts{Geant4UserEventAction}} in the doxygen documentation. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4EventAction} \\ +\bold{File name} & \tts{DDG4/src/Geant4EventAction.cpp} \\ +\bold{Type} & \tts{Geant4EventAction} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\hline +\end{tabular} + +%============================================================================= +\subsubsection{Geant4ParticlePrint} +%============================================================================= +\noindent +Geant4Action to print MC particle information. + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +\bold{Class name} & \tts{Geant4ParticlePrint} \\ +\bold{File name} & \tts{DDG4/src/Geant4ParticlePrint.cpp} \\ +\bold{Type} & \tts{Geant4EventAction} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\bold{OutputType} (bool) & Flag to steer output type. \\ + & 1: Print table of particles. \\ + & 2: Print table of particles. \\ + & 3: Print table and tree of particles. \\ +\bold{PrintHits} & Print associated hits to every particle (big output!)\\ +\hline +\end{tabular} +\newpage + + +%============================================================================= +\subsection{Sensitive Detectors} +%============================================================================= +\noindent + +%============================================================================= +\subsubsection{Geant4TrackerAction} +%============================================================================= +\noindent +Simple sensitive detector for tracking detectors. These trackers create one +single hit collection. The created hits may be written out with the output +modules described in Section~\ref{sec:ddg4-components-IO-ROOT-simple} +and~\ref{sec:ddg4-components-IO-LCIO-simple}. \\ +The basic specifications are: + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +Basics: & \\ +\hline +\bold{Class name} & \tts{Geant4SensitiveAction<Geant4Tracker>} \\ +\bold{File name} & \tts{DDG4/plugins/Geant4SDActions.cpp} \\ +\bold{Hit collection} & \tts{Name of the readout object} \\ +\bold{Hit class} & \tts{Geant4Tracker::Hit} \\ +\bold{File name} & \tts{DDG4/include/Geant4Data.h} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\hline +\end{tabular} + +%============================================================================= +\subsubsection{Geant4CalorimeterAction} +%============================================================================= +\noindent +Simple sensitive detector for calorimeters. The sensitive detector creates one +single hit collection. The created hits may be written out with the output +modules described in Section~\ref{sec:ddg4-components-IO-ROOT-simple} +and~\ref{sec:ddg4-components-IO-LCIO-simple}. \\ +The basic specifications are: + +\vspace{0.5cm} +\noindent +\begin{tabular}{ l p{10cm} } +\hline +Basics: & \\ +\hline +\bold{Class name} & \tts{Geant4SensitiveAction<Geant4Calorimeter>} \\ +\bold{File name} & \tts{DDG4/plugins/Geant4SDActions.cpp} \\ +\bold{Hit collection} & \tts{Name of the readout object} \\ +\bold{Hit class} & \tts{Geant4Calorimeter::Hit} \\ +\bold{File name} & \tts{DDG4/include/Geant4Data.h} \\ +\hline +\bold{Component Properties:} & defaults apply \\ +\hline +\end{tabular} + +\newpage + +%============================================================================= +\subsection{I/O Components} +%============================================================================= +\noindent + +%============================================================================= +\subsubsection{ROOT Output "Simple"} +\label{sec:ddg4-components-IO-ROOT-simple} +%============================================================================= +\noindent + +%============================================================================= +\subsubsection{LCIO Output "Simple"} +\label{sec:ddg4-components-IO-LCIO-simple} +%============================================================================= +\noindent + diff --git a/doc/LaTex/DDG4Manual-HighLevel.tex b/doc/LaTex/DDG4Manual-HighLevel.tex new file mode 100644 index 0000000000000000000000000000000000000000..3122c349123f457a21314efa06cf5c456be0f38f --- /dev/null +++ b/doc/LaTex/DDG4Manual-HighLevel.tex @@ -0,0 +1,160 @@ + +%============================================================================= +\section{Higher Level Components} +\label{sec:ddg4-implementation-higher-level-components} +%============================================================================= +\noindent +Layered components, which base on the general framework implement higher +level functionality such as the handling of Monte-Carlo truth associations +between simulated energy deposits and the corresponding particles or the +generic handling of input to the simulation. + +\noindent +To generalize such common behavior it is mandatory that the participating +components collaborate and understand the data components they commonly access. +The data model is shown in Figure~\ref{fig:ddg4-event-data-model}. +\begin{figure}[t] + \begin{center} + \includegraphics[width=120mm] {DDG4_event_data_model.png} + \caption{The DDG4 event data model.} + \label{fig:ddg4-event-data-model} + \end{center} +\end{figure} + +\noindent +{\bf{Please note}}, that this data model is by no means to be made persistent +and used for physics user analysis. This model is optimized to support +the simulation process and the necessary user actions to handle MC truth, +to easily and relatively fast look up and modify parent-daughter +relationships etc. This choice is based on the assumption, that the +additional overhead to convert particles at the input/output +stage is small compared to the actual resource consumption of Geant4 +to simulate the proper detector response. +On the other hand this choice has numerous advantages: +\begin{itemize}\itemcompact +\item Accepting the fact to convert input records allows to adapt + DDG4 in a simple and flexible manner to any input format. Currently + supported is the input from raw {\tts{LCIO}} files, {\tts{StdHep}} + records using {\tts{LCIO}} and {\tts{ASCII}} files using the + {\tts{HEPEvt}} format. +\item Similarly as for the input stage, also the output format + can be freely chosen by the clients. +\item No assumptions was made concerning the structure to store + information from energy deposits. Any information extract produced + by the sensitive actions can be adapted provided at the output + stage the proper conversion mechanism is present. The sensitive + detectors provided by DDG4 are {\bf{optional only and by no means mandatory}}. + User defined classes may be provided at any time. Appropriate tools + to extract MC truth information is provided at the output stage. +\item The modular approach of the action sequences described + in~\ref{sec:ddg4-user-manual-implementation-geant4action-sequences} + allows to easily extend the generation sequence to handle multiple + simultaneous interactions, event overlay or spillover response + very easily~\footnote{The handling of spillover is only possible + if during the digitization step the correct signal shape corresponding + to the shift of signal creation is taken into account.} +\end{itemize} + +\noindent +In section~\ref{sec:ddg4-implementation-input-handling} the generic mechanism +of input data handling is described. \\ +In section~\ref{sec:ddg4-implementation-particle-handling} the MC truth +handling is discussed. \\ +In section~\ref{sec:ddg4-implementation-output-handling} we describe the +output mechanism. +\newpage + +%============================================================================= +\subsection{Input Data Handling} +\label{sec:ddg4-implementation-input-handling} +%============================================================================= +\begin{figure}[t] + \begin{center} + \includegraphics[width=160mm] {DDG4_input_stage.png} + \caption{The generic handling of input sources to DDG4.} + \label{fig:ddg4-input-stage} + \end{center} +\end{figure} + +\noindent +Input handling has several stages and uses several modules: +\begin{itemize}\itemcompact +\item First the data structures \tts{Geant4PrimaryEvent}, + \tts{Geant4PrimaryInteraction} and \tts{Geant4\-Primary}\-\tts{Map} are initialized + by the action \tts{Geant4GenerationActionInit} + and attached to the {\tts{Geant4Event}} structure. +\item The initialization is then followed by any number of input modules. + Typically each input module add one interaction. Each interaction has a + unique identifier, which is propagated later to all particles. Hence all + primary particles can later be unambiguously be correlated to one of the + initial interactions. + Each instance of a \tts{Geant4InputAction} creates and fills a separate instance + of a \tts{Geant4PrimaryInteraction}. + In section~\ref{sec:ddg4-implementation-geant4inputaction} the functionality and + extensions are discussed in more detail. +\item All individual primary interactions are then merged to only single record + using the \tts{Geant4}\-\tts{Interaction}\-\tts{Merger} component. + This components fills the \tts{Geant4PrimaryInteraction} registered to the + \tts{Geant4Event}, which serves as input record for the next component, +\item the \tts{Geant4PrimaryHandler}. The primary handler creates the proper + \tts{G4PrimaryParticle} and \tts{G4PrimaryVertex} objects passed to \tts{Geant4}. + After this step all event related user interaction with Geant4 has completed, + and the detector simulation may commence. +\end{itemize} +All modules used are subclasses of the {\tts{Geant4}\-\tts{Generator}\-\tts{Action}} and must be +added to the \tts{Geant4}\-\tts{Generator}\-\tts{Action}\-\tts{Sequence} as described +in~\ref{sec:ddg4-user-manual-implementation-geant4action-sequences}. + +\noindent +An object of type {\tts{Geant4PrimaryEvent}} exists exactly once for +every event to be simulated. The empty {\tts{Geant4PrimaryEvent}} is created by the +{\tts{Geant4GenerationActionInit}} component. All higher level components may then +access the {\tts{Geant4PrimaryEvent}} object and subsequently an individual interaction +from the {\tts{Geant4Context}} using the extension mechanism as shown in +the following code: +\begin{code} +/// Event generation action callback +void SomeGenerationComponent::operator()(G4Event* event) { + /// Access the primary event object from the context + Geant4PrimaryEvent* evt = context()->event().extension<Geant4PrimaryEvent>(); + /// Access the container of interactions + const std::vector<Geant4PrimaryEvent::Interaction*>& inter = evt->interactions(); + /// Access one single interaction to be manipulated by this component + Geant4PrimaryInteraction* evt->get(m_myInteraction_identifier); + .... +\end{code} +{\bf{Please note:}} To keep components simple, each component should +only act on one interaction the component has to uniquely identify. +The identification may be implemented by e.g. an access mask passed to the +component as a property. + +%============================================================================= +\subsection{Anatomy of the Input Action} +\label{sec:ddg4-implementation-geant4inputaction} +%============================================================================= +\noindent +One input action fills one primary interaction. +\tts{Geant4InputAction} instances may be followed by decorators, which +allow to to smear primary vertex (\tts{Geant4InteractionVertexSmear}) or +to boost the primary vertex \tts{Geant4InteractionVertexBoost} and all +related particles/vertices. + + +Please note, that a possible reduction of particles in +the output record may break this unambiguous relationship between +"hits" and particles. +...... + +%============================================================================= +\subsection{Monte-Carlo Truth Handling} +\label{sec:ddg4-implementation-particle-handling} +%============================================================================= +...... +\newpage + +%============================================================================= +\section{Output Data Handling} +\label{sec:ddg4-implementation-output-handling} +%============================================================================= +...... +\newpage diff --git a/doc/LaTex/DDG4Manual-Implementation.tex b/doc/LaTex/DDG4Manual-Implementation.tex new file mode 100644 index 0000000000000000000000000000000000000000..b66d773c967d50635872421e7d93de7fe4e3da95 --- /dev/null +++ b/doc/LaTex/DDG4Manual-Implementation.tex @@ -0,0 +1,699 @@ + +%============================================================================= +\section{DDG4 Implementation} +\label{sec:ddg4-user-manual-implementation} +%============================================================================= + +\noindent +A basic design criteria of the a \DDG simulation application was to +process any user defined hook provided by Geant4 as a series of algorithmic +procedures, which could be implemented either using inheritance or by +a callback mechanism registering functions fulfilling a given signature. +Such sequences are provided for all actions mentioned in the list in +Section~\ref{sec:ddg4-user-manual-geant4-interface} as well as for +the callbacks to sensitive detectors. + +\noindent +The callback mechanism was introduced to allow for weak coupling between +the various actions. For example could an action performing monitoring +using histograms at the event level initialize or reset its histograms +at the start/end of each run. To do so, clearly a callback at the +start/end of a run would be necessary. + +\noindent +In the following sections a flexible and extensible interface to hooks +of Geant4 is discussed starting with the description of the basic +components \tts{Geant4Kernel} and \tts{Geant4Action} followed by the +implementation of the relevant specializations. +The specializations exposed are sequences of such actions, +which also call registered objects. +In later section the configuration and the combination of these components +forming a functional simulation application is presented. + +%============================================================================= +\subsection{The Application Core Object: Geant4Kernel} +\label{sec:ddg4-user-manual-implementation-geant4kernel} +%============================================================================= + +\noindent +The kernel object is the central context of a \DDG simulation application and +gives all clients access to the user hooks (see Figure~\ref{fig:ddg4-geant4-kernel}). +All Geant4 callback structures are exposed so that clients can easily +objects implementing the required interface or register callbacks with the +correct signature. Each of these action sequences is connected to an instance +of a Geant4 provided callback structure as it is shown in +Figure~\ref{fig:ddg4-g4runmanager-anatomy}. +\begin{figure}[h] + \begin{center} + \includegraphics[height=65mm] {DDG4-Geant4Kernel.png} + \caption{The main application object gives access to all sequencing actions + in a \DDG4 application. Sequence actions are only container of user actions + calling one user action after the other. Optionally single callbacks may + be registered to a user action.} + \label{fig:ddg4-geant4-kernel} + \end{center} +\end{figure} + +%============================================================================= +\subsection{Action Sequences} +\label{sec:ddg4-user-manual-implementation-geant4action-sequences} +%============================================================================= + +\noindent +As shown in + +%============================================================================= +\subsection{The Base Class of DDG4 Actions: Geant4Action} +\label{sec:ddg4-user-manual-implementation-geant4action-base} +%============================================================================= + +\noindent +The class \tts{Geant4Action} is a common component interface providing +the basic interface to the framework to +\begin{itemize}\itemcompact +\item configure the component using a property mechanism +\item provide an appropriate interface to Geant4 interactivity. The interactivity + included a generic way to change and access properties from the Geant4 UI + prompt as well as executing registered commands. +\item As shown in Figure~\ref{fig:ddg4-implementation-geant4-action}, the + base class also provides to its sub-class a reference to the \tts{Geant4Kernel} + objects through the \tts{Geant4Context}. +\end{itemize} +The \tts{Geant4Action} is a named entity and can be uniquely identified within +a sequence attached to one Geant4 user callback. +%============================================================================= +\begin{figure}[h] + \begin{center} + \includegraphics[height=30mm] {DDG4-Geant4Action.png} + \caption{The design of the common base class \tts{Geant4Action}.} + \label{fig:ddg4-implementation-geant4-action} + \end{center} +\end{figure} + +\noindent +\DDG knows two types of actions: global actions and anonymous actions. +Global actions are accessible externally from the \tts{Geant4Kernel} instance. +Global actions are also re-usable and hence may be contribute to several +action sequences (see the following chapters for details). Global actions +are uniquely identified by their name. +Anonymous actions are known only within one sequence and normally +are not shared between sequences. + +%============================================================================= +\subsubsection{The Properties of \bold{Geant4Action} Instances} +\label{sec:ddg4-implementation-geant4-action-properties} +%============================================================================= + +\noindent +Nearly any subclass of a \tts{Geant4Action} needs a flexible configuration +in order to be reused, modified etc. The implementation of the mechanism +uses a very flexible value conversion mechanism using \tts{boost::spirit}, +which support also conversions between unrelated types provided a dictionary +is present. + +\noindent +Properties are supposed to be member variables of a given action object. +To publish a property it needs to be declared in the constructor as shown here: +\begin{unnumberedcode} + declareProperty("OutputLevel", m_outputLevel = INFO); + declareProperty("Control", m_needsControl = false); +\end{unnumberedcode} +The internal setup of the \tts{Geant4Action} objects then ensure that +all declared properties will be set after the object construction to the +values set in the setup file. + +\noindent +\bold{Note:} Because the values can only be set \bold{after} the object +was constructed, the actual values may not be used in the constructor +of any base or sub-class. + +%============================================================================= +\subsection{Geant4 Action Sequences} +\label{sec:ddg4-user-manual-implementation-geant4action-sequences} +%============================================================================= + +\noindent +All Geant4 user hooks are realized as action sequences. As shown in +Figure~\ref{fig:ddg4-geant4-kernel} these sequences are accessible to the user, +who may attach specialized actions to the different action sequences. This +allows a flexible handing of specialized user actions e.g. to dynamically +add monitoring actions filling histograms or to implement alternative hit +creation mechanism in a sensitive detector for detailed detector studies. +Figure~\ref{fig:ddg4-implementation-sequence-calls} shows the schematic +call structure of an example {\tt{Geant4TrackingActionSequence}}:\\ +\begin{figure}[h] + \begin{center} + \includegraphics[width=150mm] {DDG4-TrackingActionCalls.png} + \caption{The design of the tracking action sequence. Specialized + tracking action objects inherit from the \tts{Geant4TrackingAction} + object and must be attached to the sequence.} + \label{fig:ddg4-implementation-sequence-calls} + \end{center} +\end{figure} + +\noindent +Geant4 calls the function from the virtual interface (\tts{G4UserTrackingAction}), +which is realised by the \tts{Geant4UserTrackingAction} with the single purpose to +propagate the call to the action sequence, which then calls all registered clients +of type \tts{Geant4TrackingAction}. + +\noindent +The main action sequences have a fixed name. These are +\begin{itemize} + +\item The \bold{RunAction} attached to the \tts{G4UserRunAction}, implemented + by the \tts{Geant4RunActionSequence} class and is called at the start and the end of + every run (beamOn). Members of the \tts{Geant4RunActionSequence} are of type + \tts{Geant4RunAction} and receive the callbacks by overloading the two routines: +\begin{unnumberedcode} +/// begin-of-run callback +virtual void begin(const G4Run* run); +/// End-of-run callback +virtual void end(const G4Run* run); +\end{unnumberedcode} + or register a callback with the signature {\tts{void (T::*)(const G4Run*)}} + either to receive begin-of-run or end-or-calls using the methods: +\begin{unnumberedcode} +/// Register begin-of-run callback. Types Q and T must be polymorph! +template <typename Q, typename T> void callAtBegin(Q* p, void (T::*f)(const G4Run*)); +/// Register end-of-run callback. Types Q and T must be polymorph! +template <typename Q, typename T> void callAtEnd(Q* p, void (T::*f)(const G4Run*)); +\end{unnumberedcode} + of the \tts{Geant4RunActionSequence} from the \tts{Geant4Context} object. + + +\item The \bold{EventAction} attached to the \tts{G4UserEventAction}, implemented + by the \tts{EventActionSequence} class and is called at the start and the end of + every event. Members of the \tts{Geant4EventActionSequence} are of type + \tts{Geant4EventAction} and receive the callbacks by overloading the two routines: +\begin{unnumberedcode} +/// Begin-of-event callback +virtual void begin(const G4Event* event); +/// End-of-event callback +virtual void end(const G4Event* event); +\end{unnumberedcode} + or register a callback with the signature {\tts{void (T::*)(const G4Event*)}} + either to receive begin-of-run or end-or-calls using the methods: +\begin{unnumberedcode} +/// Register begin-of-event callback +template <typename Q, typename T> void callAtBegin(Q* p, void (T::*f)(const G4Event*)); +/// Register end-of-event callback +template <typename Q, typename T> void callAtEnd(Q* p, void (T::*f)(const G4Event*)); +\end{unnumberedcode} + of the \tts{Geant4EventActionSequence} from the \tts{Geant4Context} object. + + +\item The \bold{GeneratorAction} attached to the \tts{G4VUserPrimaryGeneratorAction}, implemented + by the \tts{Geant4GeneratorActionSequence} class and is called at the start of + every event and provided all initial tracks from the Monte-Carlo generator. + Members of the \tts{Geant4GeneratorActionSequence} are of type + \tts{Geant4EventAction} and receive the callbacks by overloading the member function: +\begin{unnumberedcode} +/// Callback to generate primary particles +virtual void operator()(G4Event* event); +\end{unnumberedcode} + or register a callback with the signature {\tts{void (T::*)(G4Event*)}} + to receive calls using the method: +\begin{unnumberedcode} +/// Register primary particle generation callback. +template <typename Q, typename T> void call(Q* p, void (T::*f)(G4Event*)); +\end{unnumberedcode} + of the \tts{Geant4GeneratorActionSequence} from the \tts{Geant4Context} object. + +\end{itemize} +\begin{figure}[t] + \begin{center} + \includegraphics[width=160mm] {DDG4-TrackingAction.png} + \caption{The design of the tracking action sequence. Specialized + tracking action objects inherit from the \tts{Geant4TrackingAction} + object and must be attached to the sequence.} + \label{fig:ddg4-implementation-tracking-action} + \end{center} +\end{figure} + +\begin{itemize} +\item The \bold{TrackingAction} attached to the \tts{G4UserTrackingAction}, + implemented by the \tts{Geant4-} \tts{Tracking\-Action\-Sequence} class + and is called at the start and the end of tracking one single particle + trace through the material of the detector. + Members of the \tts{Geant4\-Tracking\-ActionSequence} are of type + \tts{Geant4TrackingAction} and receive the callbacks by overloading the member function: +\begin{unnumberedcode} +/// Pre-tracking action callback +virtual void begin(const G4Track* trk); +/// Post-tracking action callback +virtual void end(const G4Track* trk); +\end{unnumberedcode} + or register a callback with the signature {\tts{void (T::*)(const G4Step*, G4SteppingManager*)}} + to receive calls using the method: +\begin{unnumberedcode} +/// Register Pre-track action callback +template <typename Q, typename T> void callAtBegin(Q* p, void (T::*f)(const G4Track*)); +/// Register Post-track action callback +template <typename Q, typename T> void callAtEnd(Q* p, void (T::*f)(const G4Track*)); +\end{unnumberedcode} +Figure~\ref{fig:ddg4-implementation-tracking-action} show as an example +the design (class-diagram) of the \tts{Geant4TrackingAction}. + + +\item The \bold{SteppingAction} attached to the \tts{G4UserSteppingAction}, implemented + by the \tts{Geant4-} \tts{SteppingActionSequence} class and is called for each + step when tracking a particle. + Members of the \tts{Geant4SteppingActionSequence} are of type + \tts{Geant4SteppingAction} and receive the callbacks by overloading the member function: +\begin{unnumberedcode} +/// User stepping callback +virtual void operator()(const G4Step* step, G4SteppingManager* mgr); +\end{unnumberedcode} + or register a callback with the signature {\tts{void (T::*)(const G4Step*, G4SteppingManager*)}} + to receive calls using the method: +\begin{unnumberedcode} +/// Register stepping action callback. +template <typename Q, typename T> void call(Q* p, void (T::*f)(const G4Step*, + G4SteppingManager*)); +\end{unnumberedcode} + + +\item The \bold{StackingAction} attached to the + {\tts{G4UserStackingAction}}, implemented by the \tts{Geant4-}\\ + \tts{StackingActionSequence} class. + Members of the \tts{Geant4StackingActionSequence} are of type\\ + \detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_stacking_action.html} + {\tts{Geant4StackingAction}} and receive the callbacks by overloading the member functions: +\begin{unnumberedcode} +/// New-stage callback +virtual void newStage(); +/// Preparation callback +virtual void prepare(); +\end{unnumberedcode} + or register a callback with the signature {\tts{void (T::*)()}} + to receive calls using the method: +\begin{unnumberedcode} +/// Register begin-of-event callback. Types Q and T must be polymorph! +template <typename T> void callAtNewStage(T* p, void (T::*f)()); +/// Register end-of-event callback. Types Q and T must be polymorph! +template <typename T> void callAtPrepare(T* p, void (T::*f)()); +\end{unnumberedcode} +\end{itemize} + +\noindent +All sequence types support the method \tts{void adopt(T* member\_reference)} +to add the members. Once adopted, the sequence takes ownership and manages +the member. The design of all sequences is very similar. + +%============================================================================= +\subsection{Sensitive Detectors} +\label{sec:ddg4-user-manual-geant4sensitivedetectors} +%============================================================================= + +\noindent +Sensitive detectors are associated by the detector designers to all active +materials, which would produce a signal which can be read out. In Geant4 this concept +is realized by using a base class \tts{G4VSensitiveDetector}. +The mandate of a sensitive detector is the construction of hit objects +using information from steps along a particle track. +The \tts{G4VSensitiveDetector} receives +a callback at the begin and the end of the event processing and at each step +inside the active material whenever an energy deposition occurred. + +\begin{figure}[t] + \begin{center} + \includegraphics[height=110mm] {DDG4-Sensitive-detector.png} + \caption{The sensitive detector design. The actual energy deposits are + collected in user defined subclasses of the \tts{Geant4Sensitive}. + Here, as an example possible actions called \tts{TrackerHitCollector}, + \tts{TrackerDetailedHitCollector} and \tts{TrackerHitMonitor} are shown.} + \label{fig:ddg4-implementation-sensitive-detector} + \end{center} +\end{figure} + +\noindent +The sensitive actions do not necessarily deal only the collection of energy +deposits, but could also be used to simply monitor the performance of the +active element e.g. by producing histograms of the absolute value or the +spacial distribution of the depositions. + +\noindent +Within \DDG the concept of sensitive detectors is implemented as a +configurable action sequence of type +\detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_sens_det_action_sequence.html} +{\tts{Geant4SensDetActionSequence}} +calling members of the type +\detdesc{html/struct_d_d4hep_1_1_simulation_1_1_geant4_sensitive.html} +{\tts{Geant4Sensitive}} as shown in +Figure~\ref{fig:ddg4-implementation-sensitive-detector}. The actual processing +part of such a sensitive action is only called if the and of a set of +required filters of type \tts{Geant4Filter} is positive (see also +section~\ref{sec:ddg4-implementation-sensitive-detector-filters}). No filter +is also positive. Possible filters are e.g. particle filters, which ignore the +sensitive detector action if the particle is a \tts{geantino} or if the +energy deposit is below a given threshold. + +\noindent +Objects of type \tts{Geant4Sensitive} receive the callbacks by overloading the +member function: +\begin{unnumberedcode} + /// Method invoked at the beginning of each event. + virtual void begin(G4HCofThisEvent* hce); + /// Method invoked at the end of each event. + virtual void end(G4HCofThisEvent* hce); + /// Method for generating hit(s) using the information of G4Step object. + virtual bool process(G4Step* step, G4TouchableHistory* history); + /// Method invoked if the event was aborted. + virtual void clear(G4HCofThisEvent* hce); +\end{unnumberedcode} +or register a callback with the signature {\tts{void (T::*)(G4HCofThisEvent*)}} +respectively {\tts{void (T::*)(G4Step*, G4TouchableHistory*)}} +to receive callbacks using the methods: +\begin{unnumberedcode} + /// Register begin-of-event callback + template <typename T> void callAtBegin(T* p, void (T::*f)(G4HCofThisEvent*)); + /// Register end-of-event callback + template <typename T> void callAtEnd(T* p, void (T::*f)(G4HCofThisEvent*)); + /// Register process-hit callback + template <typename T> void callAtProcess(T* p, void (T::*f)(G4Step*, G4TouchableHistory*)); + /// Register clear callback + template <typename T> void callAtClear(T* p, void (T::*f)(G4HCofThisEvent*)); +\end{unnumberedcode} +Please refer to the Geant4 Applications manual from the Geant4 web page for +further details about the concept of sensitive detectors. + +%============================================================================= +\subsubsection{Helpers of Sensitive Detectors: The Geant4VolumeManager} +\label{sec:ddg4-user-manual-geant4volumemanager}%============================================================================= + +\noindent +Sooner or later, when a hit is created in a sensitive placed volume, the +hit must be associated with this volume. For this purpose \DDhep provides +the concept of the \tts{VolumeManager}, which identifies placed volumes uniquely +by a 64-bit identifier, the $CellID$. This mechanism allows to quickly +retrieve a given volume given the hit data containing the $CellID$. +The $CellID$ is a very compressed representation for any element in the +hierarchy of placed volumes to the sensitive volume in question. + +\noindent +During the simulation the reverse mechanism must be applied: Geant4 provides +the hierarchy of \tts{G4PhysicalVolumes} to the hit location and the local coordinates +of the hit within the sensitive volume. Hence to determine the volume identifier +is essential to store hits so that they can be later accessed and processed efficiently. +This mechanism is provided by the \tts{Geant4VolumeManager}. Clients typically do not +interact with this object, any access necessary is provided by the +\tts{Geant4Sensitive} action: +\begin{unnumberedcode} + /// Method for generating hit(s) using the information of G4Step object. + bool MySensitiveAction:process(G4Step* step,G4TouchableHistory* /*hist*/ ) { + ... + Hit* hit = new Hit(); + // *** Retrieve the cellID *** + hit->cellID = cellID(step); + ... + } +\end{unnumberedcode} +The call is realized using a member function provided by the +\tts{Geant4Sensitive} action: +\begin{unnumberedcode} + /// Returns the cellID of the sensitive volume corresponding to the step + /** The CellID is the VolumeID + the local coordinates of the sensitive area. + * Calculated by combining the VolIDS of the complete geometry path (Geant4TouchableHistory) + * from the current sensitive volume to the world volume + */ + long long int cellID(G4Step* step); +\end{unnumberedcode} + +\noindent +\bold{Note:}\\ +The \tts{Geant4VolumeManager} functionality is not for free! It requires that + + +\noindent +-- match Geant4 volume with TGeo volume + +%============================================================================= +\subsubsection{DDG4 Intrinsic Sensitive Detectors} +%============================================================================= +\noindent +Currently there are two generic sensitive detectors implemented in DDG4: +\begin{itemize}\itemcompact +\item The \tts{Geant4TrackerAction}, which may be used to handle tracking devices. + This sensitive detector produces one hit for every energy deposition of Geant4 + i.e. for every callback to +\begin{unnumberedcode} + /// Method for generating hit(s) using the information of G4Step object. + virtual bool process(G4Step* step, G4TouchableHistory* history); +\end{unnumberedcode} + See the implementation file + \detdesc{html/_geant4_s_d_actions_8cpp_source.html}{DDG4/plugins/Geant4SDAction.cpp} + for details. The produced hits are of type + \detdesc{html/_geant4_data_8h_source.html}{Geant4Tracker::Hit}. + +\item The \tts{Geant4CalorimeterAction}, which may be used to handle + generic calorimeter like devices. + This sensitive detector produces at most one hit for every cell in the calorimeter. + If several tracks contribute to the energy deposit of this cell, the contributions + are added up. + See the implementation file + \detdesc{html/_geant4_s_d_actions_8cpp_source.html}{DDG4/plugins/Geant4SDAction.cpp} + for details. The produced hits are of type + \detdesc{html/_geant4_data_8h_source.html}{Geant4Calorimeter::Hit}. + propagate the MC truth information with respect to each track kept in the + particle record. +\end{itemize} + +\noindent +Both sensitive detectors use the \tts{Geant4VolumeManager} discussed in +section~\ref{sec:ddg4-user-manual-geant4volumemanager} to identify the sensitive elements. + +\noindent +\bold{PLEASE NOTE:}\\ +The above palette of generic sensitive detectors only contains two very +often used implementations. We hope, that this palette over time grows from +external contributions of other generic sensitive detectors. We would be happy +to extend this palette with other generic implementations. One example would +be the handling of the simulation response for optical detectors like RICH-Cerenkov +detectors. + +%============================================================================= +\subsubsection{Sensitive Detector Filters} +\label{sec:ddg4-implementation-sensitive-detector-filters} +%============================================================================= + +\noindent +The concept of filters allows to build more flexible sensitive detectors by +restricting the hit processing of a given instance of a sensitive action. + +\begin{itemize}\itemcompact +\item Examples would be to demand a given particle type before a sensitive action is +invoked: a sensitive action dealing with optical photons (RICH detectors, etc), +would e.g. not be interested in energy depositions of other particles. +A filter object restricting the particle type to optical photons would +be appropriate. +\item Another example would be to implement a special action instance, which would +be only called if the filter requires a minimum energy deposit. +\end{itemize} +There are plenty of possible applications, hence we would like +to introduce this feature here. + +\noindent +Filters are called by Geant4 before the +hit processing in the sensitive detectors start. The global filters +may be shared between many sensitive detectors. Alternatively filters +may be directly attached to the sensitive detector in question. +Attributes are directly passed as properties to the filter action. + +\noindent +Technically do \tts{Geant4Filter} objects inherit from the base class +\tts{Geant4Filter} (see Figure~\ref{fig:ddg4-implementation-sensitive-detector-filters}. +Any filter inherits from the common base class \tts{Geant4Filter}, then +several specializations may be configured like filters to select/reject +particles, to specify the minimal energy deposit to be processed etc. +A sensitive detector is called if the filter callback with the signature +returns a true result: +\begin{unnumberedcode} + /// Filter action. Return true if hits should be processed + virtual bool operator()(const G4Step* step) const; +\end{unnumberedcode} +\begin{figure}[h] + \begin{center} + \includegraphics[height=65mm] {DDG4-SensitiveFilterClasses.png} + \caption{The sensitive detector filters design. The shown class + diagram is actually implemented.} + \label{fig:ddg4-implementation-sensitive-detector-filters} + \end{center} +\end{figure} + +\newpage + +%============================================================================= +\subsection{The Geant4 Physics List} +\label{sec:ddg4-implementation-physics-list} +%============================================================================= +\noindent +Geant4 provides the base class \tts{G4VUserPhysicsList}, which allows users +to implement customized physics according to the studies to be made. +Any user defined physics list must provide this interface. DDG4 provides such an interface +through the ROOT plugin mechanism using the class \tts{G4VModularPhysicsList}. +The flexibility of \DDG allows for several possibilities to setup the Geant4 +physics list. Instead of explicitly coding the physics list, \DDG foresees the +usage of the plugin mechanism to instantiate the necessary calls to Geant4 in a +sequence of actions: +\begin{itemize} +\item The \bold{physics list} is realized as a sequence of actions of type + \detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_physics_list_action_sequence.html} + {\tts{Geant4PhysicsListActionSequence}}. + Members of the \detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_physics_list_action_sequence.html} + {\tts{Geant4PhysicsListActionSequence}} are of type + \detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_physics_list.html} + {\tts{Geant4PhysicsList}} and receive the callbacks by overloading + the member functions: +\begin{unnumberedcode} + /// Callback to construct the physics constructors + virtual void constructProcess(Geant4UserPhysics* interface); + /// constructParticle callback + virtual void constructParticles(Geant4UserPhysics* particle); + /// constructPhysics callback + virtual void constructPhysics(Geant4UserPhysics* physics); +\end{unnumberedcode} + or register a callback with the signature {\tts{void (T::*)(Geant4UserPhysics*)}} + to receive calls using the method: +\begin{unnumberedcode} + /// Register process construction callback t + template <typename Q, typename T> void constructProcess(Q* p, void (T::*f)(Geant4UserPhysics*)); + /// Register particle construction callback + template <typename Q, typename T> void constructParticle(Q* p, void (T::*f)(Geant4UserPhysics*)); +\end{unnumberedcode} + The argument of type \detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_user_physics.html} + {\tts{Geant4UserPhysics}} provides a basic interface to the original + \tts{G4VModular}- \tts{PhysicsList}, which allows to register physics constructors etc. + +\item In most of the cases the above approach is an overkill and often even too flexible. + Hence, alternatively, the physics list may consist of a single entry of type + \detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_physics_list.html} + {\tts{Geant4PhysicsList}}. +\end{itemize} + +\noindent +The basic implementation of the \tts{Geant4PhysicsList} supports the usage of various +\begin{itemize}\itemcompact +\item \detdesc{html/_geant4_particles_8cpp_source.html}{particle constructors}, + such as single particle constructors like + \tts{G4Gamma} or \tts{G4Proton}, or whole particle groups like + \tts{G4BosonConstructor} or \tts{G4IonConstrutor}, +\item \detdesc{html/_geant4_processes_8cpp_source.html}{physics process constructors}, + such as e.g. \tts{G4GammaConversion}, + \tts{G4PhotoElectricEffect} or\\ \tts{G4ComptonScattering}, +\item \detdesc{html/_geant4_physics_constructors_8cpp_source.html}{physics constructors} + combining particles and the corresponding + interactions, such as\\ e.g. \tts{G4OpticalPhysics}, + \tts{HadronPhysicsLHEP} or \tts{G4HadronElasticPhysics} and +\item \detdesc{html/_geant4_particles_8cpp_source.html}{predefined Geant4 physics lists}, + such as \tts{FTFP\_BERT}, + \tts{CHIPS} or \tts{QGSP\_INCLXX}. This option is triggered by the + content of the string property "extends" of the \tts{Geant4Kernel::physicsList()} action. +\end{itemize} +These constructors are internally connected to the above callbacks to register themselves. +The constructors are instantiated using the ROOT plugin mechanism. + +\noindent +The description of the above interface is only for completeness. The basic idea is, +that the physics list with its particle and physics constructors is configured +entirely data driven using the setup mechanism described in the following +chapter. However, DDG4 is not limited to the data driven approach. Specialized +physics lists may be supplied, but there should be no need. +New physics lists could always be composed by actually providing new physics +constructors and actually publishing these using the factory methods: +\begin{code} +// Framework include files +#include "DDG4/Factories.h" + +#include "My_Very_Own_Physics_Constructor.h" +DECLARE_GEANT4_PHYSICS(My_Very_Own_Physics_Constructor) +\end{code} +where \tts{My\_Very\_Own\_Physics\_Constructor} represents a sub-class of +\tts{G4VPhysicsConstructor}. + +\newpage +%============================================================================= +\subsection{The Support of the Geant4 UI: \tts{Geant4UIMessenger}} +\label{sec:ddg4-user-manual-geant4action-base} +%============================================================================= + +\noindent +The support of interactivity in Geant4 is mandatory to debug detector +setups in small steps. The Geant4 toolkit did provide for this reason +a machinery of UI commands. +\begin{figure}[h] + \begin{center} + \includegraphics[height=70mm] {DDG4-UIMessenger.png} + \caption{The design of the \tts{Geant4UIMessenger} class responsible for + the interaction between the user and the components of \DDG and Geant4.} + \label{fig:ddg4-tracking-action} + \end{center} +\end{figure} + +\noindent +The UI control is enabled, as soon as the property "Control" (boolean) is set to true. +Be default all properties of the action are exported. +Similar to the callback mechanism described above it is also feasible to +register any object callback invoking a method of a \tts{Geant4Action}-subclass. + +\noindent +The following (shortened) screen dump illustrates the usage of the +generic interface any Geant4Action offers: +\begin{unnumberedcode} +Idle> ls +Command directory path : / + Sub-directories : + /control/ UI control commands. + /units/ Available units. + /process/ Process Table control commands. + /ddg4/ Control for all named Geant4 actions + ... +Idle> cd /ddg4 +Idle> ls +... +Control for all named Geant4 actions + + Sub-directories : + /ddg4/RunInit/ Control hierarchy for Geant4 action:RunInit + /ddg4/RunAction/ Control hierarchy for Geant4 action:RunAction + /ddg4/EventAction/ Control hierarchy for Geant4 action:EventAction + /ddg4/GeneratorAction/ Control hierarchy for Geant4 action:GeneratorAction + /ddg4/LCIO1/ Control hierarchy for Geant4 action:LCIO1 + /ddg4/Smear1/ Control hierarchy for Geant4 action:Smear1 + /ddg4/PrimaryHandler/ Control hierarchy for Geant4 action:PrimaryHandler + /ddg4/TrackingAction/ Control hierarchy for Geant4 action:TrackingAction + /ddg4/SteppingAction/ Control hierarchy for Geant4 action:SteppingAction + /ddg4/ParticleHandler/ Control hierarchy for Geant4 action:ParticleHandler + /ddg4/UserParticleHandler/ Control hierarchy for Geant4 action:UserParticleHandler + ... +Idle> ls Smear1 +Command directory path : /ddg4/Smear1/ + ... + Commands : + show * Show all properties of Geant4 component:Smear1 + Control * Property item of type bool + Mask * Property item of type int + Name * Property item of type std::string + Offset * Property item of type ROOT::Math::LorentzVector<ROOT::Math::PxPyPzE4D<double> > + OutputLevel * Property item of type int + Sigma * Property item of type ROOT::Math::LorentzVector<ROOT::Math::PxPyPzE4D<double> > + name * Property item of type std::string +Idle> Smear1/show +PropertyManager: Property Control = True +PropertyManager: Property Mask = 1 +PropertyManager: Property Name = 'Smear1' +PropertyManager: Property Offset = ( -20 , -10 , -10 , 0 ) +PropertyManager: Property OutputLevel = 4 +PropertyManager: Property Sigma = ( 12 , 8 , 8 , 0 ) +PropertyManager: Property name = 'Smear1' + +Idle> Smear1/Offset (200*mm, -3*mm, 15*mm, 10*ns) +Geant4UIMessenger: +++ Smear1> Setting property value Offset = (200*mm, -3*mm, 15*mm, 10*ns) + native:( 200 , -3 , 15 , 10 ). +Idle> Smear1/show +... +PropertyManager: Property Offset = ( 200 , -3 , 15 , 10 ) + +\end{unnumberedcode} + +\newpage diff --git a/doc/LaTex/DDG4Manual-Introduction.tex b/doc/LaTex/DDG4Manual-Introduction.tex new file mode 100644 index 0000000000000000000000000000000000000000..f65f55cd33433f038ae58634ad843bf1d7f88abf --- /dev/null +++ b/doc/LaTex/DDG4Manual-Introduction.tex @@ -0,0 +1,108 @@ + +%============================================================================= +\section{Introduction} +\label{sec:ddg4-user-manual-introduction} +%============================================================================= +\noindent +This manual should introduce to the DDG4 framework. +One goal of \DDG is to easily configure the simulation applications +capable of simulating the physics response of detector configurations +as they are used for example in high energy physics experiments. +In such simulation programs the user normally has to define the +experimental setup in terms of its geometry and in terms of its +active elements which sample the detector response. + +\noindent +The goal of \DDG is to generalize the configuration of a simulation +application to a degree, which does not force users to write code +to test a detector design. At the same time it should of course +be feasible to supply specialized user written modules which are supposed +to seamlessly operate together with standard modules supplied by the toolkit. +Detector-simulation depends strongly on the use of an underlying simulation +toolkit, the most prominent candidate nowadays being Geant4~\cite{bib:geant4}. +\DDhep supports simulation activities with Geant4 providing +an automatic translation mechanism between geometry representations. +The simulation response in the active elements of the detector +is strongly influenced by the technical +choices and precise simulations depends on the very specific detection techniques. + +\noindent +Similar to the aim of \DDhep~\cite{bib:DD4hep}, +where with time a standard palette of detector +components developed by users should become part of the toolkit, +\DDG also hopes to provide a standard palette of components used +to support simulation activities for detector layouts +where detector designers may base the simulation of a planned experiment +on these predefined components for initial design and optimization +studies. The longterm vision is to construct simulation applications +writing only new components not yet present i.e. the main work will be to +select the appropriate components from the palette and connect them +to a functional program. + +\noindent +This is not a manual to Geant4 nor the basic infrastructure of \DDhep. +It is assumed that this knowledge is present and the typical glossary +is known. + +%============================================================================= +\section{The Geant4 User Interface} +\label{sec:ddg4-user-manual-geant4-interface} +%============================================================================= + +\noindent +The Geant4 simulation toolkit~\cite{bib:geant4} implements a very complex +machinery to simulate the energy deposition of particles traversing materials. +To ease its usage for the clients and to shield clients from the complex +internals when actually implementing a simulation applications for a +given detector design, it provides several user hooks +as shown in Figure~\ref{fig:ddg4-g4runmanager-anatomy}. Each of these hooks +serves a well specialized purpose, but unfortunately also leads to very +specialized applications. One aim of \DDG is to formalize these user +actions so that the invocation at the appropriate time may be purely +data driven. +\begin{figure}[h] + \begin{center} + \includegraphics[height=70mm] {DDG4-G4RunManagerAnatomy.png} + \caption{The various user hooks provided by Geant4. Not shown here + is the callback system interfacing to the active elements + of the detector design.} + \label{fig:ddg4-g4runmanager-anatomy} + \end{center} +\end{figure} + +\noindent +In detail the following object-hooks allow the client to define user provided actions: +\begin{itemize}\itemcompact +\item The \bold{User Physics List} allows the client to customize and define + the underlying physics process(es) which define the particle interactions + inside the detector defined with the geometry description. + These interactions define the detector response in terms of + energy depositions. +\item The \bold{Run Action} is called once at the start and end of a run. + i.e. a series of generated events. These two callbacks + allow clients to define run-dependent actions such as statistics + summaries etc. +\item The \bold{Primary Generator Action} is called for every event. + During the callback all particles are created which form the + microscopic kinematic action of the particle collision. + This input may either origin directly from an event generator program + or come from file. +\item The \bold{Event Action} is called once at the start and the end of each event. + It is typically used for a simple analysis of the processed event. + If the simulated data should be written to some persistent medium, + the call at the end of the event processing is the appropriate place. +\item The \bold{Tracking Action} +\item The \bold{Stepping Action} +\item The \bold{Stacking Action} +\end{itemize} +\noindent +Geant4 provides all callbacks with the necessary information in the form of +appropriate arguments. + +\noindent +Besides the callback system, Geant4 provides callbacks whenever a particle +traverses a sensitive volume. These callbacks are called +- similar to event actions - once at the start and the end of the event, +but in addition, if either the energy deposit of a particle in the +sensitive volume exceeds some threshold. The callbacks are formalized within +the base class \tts{G4VSensitiveDetector}. diff --git a/doc/LaTex/DDG4Manual-MT.tex b/doc/LaTex/DDG4Manual-MT.tex new file mode 100644 index 0000000000000000000000000000000000000000..af921b5399fe156cf058aca9b114403289a5b74c --- /dev/null +++ b/doc/LaTex/DDG4Manual-MT.tex @@ -0,0 +1,359 @@ + +%============================================================================= +\section{Multi-Threading in \DDG} +\label{sec:ddg4-multi-threading} +%============================================================================= +\subsection{Introductory Remarks} +\label{sec:ddg4-multi-threading-introduction} +%============================================================================= +\noindent +Multi-threading as supported by Geant4 is event driven. This means that +the simulation of a given event is handled by one single thread. +Geant4 provides specific extensions to ease the users the use of its +multi-threaded extensions~\cite{bib:Geant4-multi-threading}~\footnote{Please +note that the whole of Geant4 and your client code must be compiled with +the compile flag ${\tts{-DGEANT4_BUILD_MULTITHREADED=ON}}$}. +These extension divide in a formalized manner all actions to be performed +to setup a Geant4 multi-threaded program into + +\begin{itemize}\itemcompact +\item {\bf{common}} actions to be performed and shared by all threads. +This includes the setup of the geometry and the physics list. The +other main area are +\item {\bf{thread-specific}} actions to be performed for each thread. +These are composed by the user actions called during the processing of +each run. These are the run-, event-, generation-, tracking-, +stepping and stacking actions. +\end{itemize} + +\noindent +To understand the interplay between \DDG and Geant4 let us quickly +recapitulate the Geant4 mechanism how to configure multiple threads. +The setup of a multi-threaded application in Geant4 is centered around +two additional classes, which both deal with single- and multi-threaded +issues: + +\begin{itemize}\itemcompact +\item {\tts{G4VUserActionInitialization}} class with 2 major callbacks: + {\tts{Build()}} which is executed for each {\bf{worker thread}} and + {\tts{BuildForMaster()}} which is executed for master thread only. +\item {\tts{G4VUserDetectorConstruction}} class with the callbacks + {\tts{Construct()}}, where the shared geometry is constructed and + {\tts{ConstructSDandField()}} where the sensitive detectors and the + electro magnetic fields are provided. +\end{itemize} + +\noindent +Both these Geant4 provided hooks are modeled in the standard \DDG +way as action queues, which allow a modular and fine grained setup +as shown in Figure~\ref{fig:ddg4-user-initialization} and +Figure~\ref{fig:ddg4-detector-initialization}. +\begin{figure}[t] + \begin{center} + \includegraphics[width=140mm] {DDG4-User-Initialization.png} + \caption{The Geant4 user initialization sequence to setup DDG4 + in multi-threaded mode. The callbacks {\tts{buildMaster()}} + is only called in multi-threaded mode.} + \label{fig:ddg4-user-initialization} + \end{center} +\end{figure} + +\noindent +The \DDG framework ensures that all user callbacks are installed properly +to the Geant4 run manager, which calls them appropriately at the correct time. + +\noindent +\DDG provides three callbacks for each sequence. Each callback receives +a temporary context argument, which may be used to shortcut access +to basic useful quantities: +\begin{code} + struct Geant4DetectorConstructionContext { + /// Reference to geometry object + Geometry::LCDD& lcdd; + /// Reference to the world after construction + G4VPhysicalVolume* world; + /// The cached geometry information + Geant4GeometryInfo* geometry; + /// G4 User detector initializer + G4VUserDetectorConstruction* detector; +}; +\end{code} + +\begin{figure}[h] + \begin{center} + \includegraphics[width=140mm] {DDG4-Detector-Construction.png} + \caption{The Geant4 detector initialization sequence to setup DDG4. + If supplied, Geant4 calls the components both, in the single-threaded + and in the multi-threaded mode.} + \label{fig:ddg4-detector-initialization} + \end{center} +\end{figure} + +The callbacks and the expected functionality are: +\begin{enumerate} +\item First the detector geometry is constructed. This happens in the callback + {\tts{constructGeo(...)}}. If a standard \DDhep geometry + is present, this is translation of the geometry could be done by simply + calling the plugin {\tts{Geant4DetectorGeometryConstruction}}. + Alternatively a user defined plugin could perform this action. +\item Next the electromagnetic fields for the Geant4 particle tracking is + constructed. A generic plugin {\tts{Geant4FieldTrackingConstruction}} + may be attached. The corresponding setup parameters are listed in + Section~\ref{sec:existing-ddg4-components}. + Alternatively a user defined plugin could perform this action. +\item Finally the Geant4 sensitive detectors are instantiated and attached + to the sensitive volumes. For generic setups the plugin + {\tts{Geant4DetectorSensitivesConstruction}} may be attached. + Alternatively a user defined plugin could perform this action. +\end{enumerate} + +%============================================================================= +\subsection{Thread related contexts} +\label{sec:ddg4-thread-save context} +%============================================================================= +\noindent +\DDG provides thread related context, which may be accessed or modified +by user code. This context, the {\tts{Geant4Context}} and it's sub-components, +as discussed in Section~\ref{sec:ddg4-implementation-higher-level-components} +are available as separate instances for each event and as such +also independently for each worker thread. Hence, no user level locking of the +event context is necessary in any worker thread. + +%============================================================================= +\subsection{Thread-Shared Components} +\label{sec:ddg4-multi-threaded-shared-actions} +%============================================================================= +\noindent +Some actions, though executed in the context of a single thread context +may only execute as singletons. An example would be a {\tts{GeneratorAction}}, +which read input events from file. Clearly the reading of data from +file must be protected and the reading of one event in a given thread +must finish, before the next thread may take over. +Another example are data analysis components, which e.g. fill a histogram. +Typically the filling mechanism of a histogram is not thread safe and hence must +be protected. + +\noindent +To solve such issues all actions, which may involve such shared +activities, a shared action is provided, which adopts a singleton +instance and executes the relevant callbacks in a protected manner. +The shared actions execute the user component in a thread safe envelope. + +\noindent +Clearly no run- or event related state in such shared actions may be +carried by the component object across callbacks. The action objects +may not be aware of the event related context outside the callback. +Default implementations for such shared actions exist for +\begin{itemize}\itemcompact +\item the {\tts{Geant4RunAction}}, where the calls to + {\tts{Geant4RunAction::begin}} and {\tts{Geant4RunAction::end}} + are {\bf{globally}} locked and the sequential execution of + the entire sequence is ensured; +\item the {\tts{Geant4EventAction}}, +\item the {\tts{Geant4TrackingAction}}, +\item the {\tts{Geant4SteppingAction}} and +\item the {\tts{Geant4StackingAction}}. +\end{itemize} +In the latter cases the framework ensures thread safety, but does +not ensure the reentrant execution order of the entire sequence. + +\noindent +{\bf{General Remark:}} +\noindent +Simple callbacks registered to the run-, event, etc.-actions cannot +be protected. These callbacks may under no circumstances use any +event related state information of the called object. + +%============================================================================= +\subsection{Backwards- and Single-Thread-Compatibility} +\label{sec:ddg4-multi-threading-backwards} +%============================================================================= +\noindent +As in the single threaded mode of Geant4, also in the multi-threaded +mode all user actions are called by an instance of the {\tts{G4RunManager}} +or a sublass thereof, the {\tts{G4MTRunManager}}~\cite{bib:Geant4-multi-threading}. + +\noindent +If the recommended actions in sub-section~\ref{sec:ddg4-multi-threading-introduction} +are used to configure the Geant4 application, then in a rather transparent +way both single-threaded and multi-threaded setups can coexist simply by +changing the concrete instance of the {\tts{G4RunManager}}. There is one +single exception: The user initialization function +{\tts{G4VUserActionInitialization::BuildForMaster()}} is {\bf{only}} executed +in multi-threaded mode. For this reason, we deprecate the usage. Try +to find solutions, without master specific setup using e.g. shared actions. + +%============================================================================= +\subsection{Support for Python Setup in Multi-Threading Mode} +\label{sec:ddg4-multi-threading-python} +%============================================================================= +\noindent +The setup of \DDG in multi-threaded mode requires separate callbacks for +the global configuration (geometry, etc.) and the configuration of the worker +threads. In python this setup is performed within {\rm{python callable}} +objects, which are either functions or member functions of objects. +These functions may have arguments. The python specific configuration actions +\begin{itemize}\itemcompact +\item The user initialization action + {\tts{Geant4PythonInitialization}} allows to configure python callbacks + for the master and the worker thread setup using the calls: + \begin{code} + /// Set the Detector initialization command + void setMasterSetup(PyObject* callable, PyObject* args); + /// Set the field initialization command + void setWorkerSetup(PyObject* callable, PyObject* args); \end{code} + to be used in python as a call sequence within the master thread: + \begin{code} + init_seq = kernel.userInitialization(True) + init_action = UserInitialization(kernel,'Geant4PythonInitialization/PyG4Init') + init_action.setWorkerSetup(worker_setup_call, < worker_args > ) + init_action.setMasterSetup(master_setup_call, < master_args > ) + init_seq.adopt(init_action) \end{code} + The callback argument list $< worker\_args >$ and $< master\_args >$ + are python tuples containing all arguments expected by the callable objects + $worker\_setup\_call$ and $master\_setup\_call$ respecyively. + The class {\tts{Geant4PythonInitialization}} is a subclass of + {\tts{Geant4UserInitialization}} and will call the provided functions + according to the protocol explained earlier in this section. + If a callback is not set, the corresponding actiion is not executed. +\item The detector construction action + {\tts{Geant4PythonDetectorConstruction}} is the corresponding + python action to populate the detector construction sequencer. + and supports three ccallbacks: + \begin{code} + /// Set the Detector initialization command + void setConstructGeo(PyObject* callable, PyObject* args); + /// Set the field initialization command + void setConstructField(PyObject* callable, PyObject* args); + /// Set the sensitive detector initialization command + void setConstructSensitives(PyObject* callable, PyObject* args); \end{code} + to be used in python as call sequence within the master thread: + \begin{code} + init_seq = self.master().detectorConstruction(True) + init_action = DetectorConstruction(self.master(),name_type) + init_action.setConstructGeo(geometry_setup_call, < geometry_args > ) + init_action.setConstructField(field_setup_call, < field_args > ) + init_action.setConstructSensitives(sensitives_setup_call, < sensitives_args >) + init_seq.adopt(init_action) \end{code} + If any of the three callback is not set, the corresponding actiion is not executed. + Hereby are $geometry\_setup\_call$, $field\_setup\_call$ and $sensitives\_setup\_call$ + the callable objects to configure the geometry, the tracking field + and the sensitive detectors. + $< geometry\_args >$, $< field\_args >$ and $< sensitives\_args >$ are + the corresponding callable arguments in the form of a python tuple object. +\end{itemize} + +\noindent +All python callbacks are supposed to return the integer '1' on success. +Any other return code is assumed to be failure. + +%============================================================================= +\subsection{\DDG Multi-Threading Example} +\label{sec:ddg4-multi-threading-example} +%============================================================================= +\begin{code} +""" + + DD4hep simulation example setup DDG4 + in multi-threaded mode using the python configuration + + @author M.Frank + @version 1.0 + +""" +import os, time, DDG4 + +def setupWorker(geant4): + kernel = geant4.kernel() + print '#PYTHON: +++ Creating Geant4 worker thread ....' + print "#PYTHON: Configure Run actions" + run1 = DDG4.RunAction(kernel,'Geant4TestRunAction/RunInit') + ... + print "#PYTHON: Configure Event actions" + prt = DDG4.EventAction(kernel,'Geant4ParticlePrint/ParticlePrint') + kernel.eventAction().adopt(prt) + ... + print "\n#PYTHON: Configure I/O\n" + evt_root = geant4.setupROOTOutput('RootOutput','CLICSiD_'+time.strftime('%Y-%m-%d_%H-%M')) + ... + gen = DDG4.GeneratorAction(kernel,"Geant4GeneratorActionInit/GenerationInit") + kernel.generatorAction().adopt(gen) + print "#PYTHON: First particle generator: pi+" + gen = DDG4.GeneratorAction(kernel,"Geant4IsotropeGenerator/IsotropPi+"); + ... + print "#PYTHON: Merge all existing interaction records" + gen = DDG4.GeneratorAction(kernel,"Geant4InteractionMerger/InteractionMerger") + kernel.generatorAction().adopt(gen) + print "#PYTHON: Finally generate Geant4 primaries" + gen = DDG4.GeneratorAction(kernel,"Geant4PrimaryHandler/PrimaryHandler") + kernel.generatorAction().adopt(gen) + print "#PYTHON: ....and handle the simulation particles." + part = DDG4.GeneratorAction(kernel,"Geant4ParticleHandler/ParticleHandler") + kernel.generatorAction().adopt(part) + + user = DDG4.Action(kernel,"Geant4TCUserParticleHandler/UserParticleHandler") + ... + part.adopt(user) + print '#PYTHON: +++ Geant4 worker thread configured successfully....' + return 1 + +def setupMaster(geant4): + kernel = geant4.master() + print '#PYTHON: +++ Setting up master thread for ',kernel.NumberOfThreads,' workers.' + return 1 + +def setupSensitives(geant4): + print "#PYTHON: Setting up all sensitive detectors" + geant4.printDetectors() + print "#PYTHON: First the tracking detectors" + seq,act = geant4.setupTracker('SiVertexBarrel') + ... + print "#PYTHON: Now setup the calorimeters" + seq,act = geant4.setupCalorimeter('EcalBarrel') + ... + return 1 + +def run(): + kernel = DDG4.Kernel() + lcdd = kernel.lcdd() + install_dir = os.environ['DD4hepINSTALL'] + DDG4.Core.setPrintFormat("%-32s %6s %s") + kernel.loadGeometry("file:"+install_dir+"/DDDetectors/compact/SiD.xml") + DDG4.importConstants(lcdd) + + kernel.NumberOfThreads = 3 + geant4 = DDG4.Geant4(kernel,tracker='Geant4TrackerCombineAction') + print "# Configure UI" + geant4.setupCshUI() + + print "# Geant4 user initialization action" + geant4.addUserInitialization(worker=setupWorker, worker_args=(geant4,), + master=setupMaster,master_args=(geant4,)) + print "# Configure G4 geometry setup" + seq,act = geant4.addDetectorConstruction("Geant4DetectorGeometryConstruction/ConstructGeo") + + print "# Configure G4 sensitive detectors: python setup callback" + seq,act = geant4.addDetectorConstruction("Geant4PythonDetectorConstruction/SetupSD", + sensitives=setupSensitives,sensitives_args=(geant4,)) + print "# Configure G4 sensitive detectors: atach'em to the sensitive volumes" + seq,act = geant4.addDetectorConstruction("Geant4DetectorSensitivesConstruction/ConstructSD") + + print "# Configure G4 magnetic field tracking" + seq,field = geant4.addDetectorConstruction("Geant4FieldTrackingConstruction/MagFieldTrackingSetup") + field.stepper = "HelixGeant4Runge" + field.equation = "Mag_UsualEqRhs" + field.eps_min = 5e-05 * mm + ... + print "# Setup random generator" + rndm = DDG4.Action(kernel,'Geant4Random/Random') + rndm.Seed = 987654321 + rndm.initialize() + print "# Now build the physics list:" + phys = geant4.setupPhysics('QGSP_BERT') + geant4.run() + +if __name__ == "__main__": + run() +\end{code} + +\newpage \ No newline at end of file diff --git a/doc/LaTex/DDG4Manual-Setup.tex b/doc/LaTex/DDG4Manual-Setup.tex new file mode 100644 index 0000000000000000000000000000000000000000..60dc4ce23db0ed3253ed07309a82595d8b2495b8 --- /dev/null +++ b/doc/LaTex/DDG4Manual-Setup.tex @@ -0,0 +1,725 @@ + +%============================================================================= +\section{Setting up DDG4} +\label{sec:ddg4-implementation-setup} +%============================================================================= + +\noindent +\DDG offers several possibilities to configure a simulation application +using +\begin{itemize}\itemcompact +\item XML files, +\item by coding a setup script loaded from the \tts{ROOT} interpreter + with the AClick mechanism. +\item by creating a setup script using \tts{python} and + \tts{ROOT}'s reflection mechanism exposed by \tts{PyROOT}. +\end{itemize} +The following subsection describe these different mechanism. An attempt was made +to match the naming conventions of all approaches where possible. + +%============================================================================= +\subsection{Setting up DDG4 using XML} +\label{sec:ddg4-implementation-setup-xml} +%============================================================================= + +\noindent +A special plugin was developed to enable the configuration of \DDG using +XML structures. These files are parsed identically to the geometry setup +in \DDhep the only difference is the name of the root-element, which for +\DDG is \tts{<geant4\_setup>}. +The following code snippet shows the basic structure of a \DDG setup file: +\begin{unnumberedcode} +<geant4_setup> + <physicslist> ,,, </physicslist> <!-- Definition of the physics list --> + <actions> ... </actions> <!-- The list of global actions --> + <phases> ... </phases> <!-- The definition of the various phases --> + <filters> ... </filters> <!-- The list of global filter actions --> + <sequences> ... </sequences> <!-- The list of defined sequences --> + <sensitive_detectors> ... </sensitive_detectors> <!-- The list of sensitive detectors --> + <properties> ... </properties> <!-- Free format option sequences --> +</geant4_setup> +\end{unnumberedcode} +To setup a \DDG4 application any number of xml setup files may be interpreted +iteratively. In the following subsections the content of these first level sub-trees will +be discussed. + +%============================================================================= +\subsubsection{Setup of the Physics List} +\label{sec:ddg4-setup-xml-physicslist} +%============================================================================= + +\noindent +The main tag to setup a physics list is \tts{<physicslist>} with the +\tts{name} attribute defining the instance of the \tts{Geant4PhysicsList} object. +An example code snippet is shown below in Figure~\ref{fig:ddg4-setup-xml-physicslist}. + +\begin{code} +<geant4_setup> + <physicslist name="Geant4PhysicsList/MyPhysics.0"> + + <extends name="QGSP_BERT"/> <!-- Geant4 basic Physics list --> + + <particles> <!-- Particle constructors --> + <construct name="G4Geantino"/> + <construct name="G4ChargedGeantino"/> + <construct name="G4Electron"/> + <construct name="G4Gamma"/> + <construct name="G4BosonConstructor"/> + <construct name="G4LeptonConstructor"/> + <construct name="G4MesonConstructor"/> + <construct name="G4BaryonConstructor"/> + ... + </particles> + + <processes> <!-- Process constructors --> + <particle name="e[+-]" cut="1*mm"> + <process name="G4eMultipleScattering" ordAtRestDoIt="-1" ordAlongSteptDoIt="1" + ordPostStepDoIt="1"/> + <process name="G4eIonisation" ordAtRestDoIt="-1" ordAlongSteptDoIt="2" + ordPostStepDoIt="2"/> + </particle> + <particle name="mu[+-]"> + <process name="G4MuMultipleScattering" ordAtRestDoIt="-1" ordAlongSteptDoIt="1" + ordPostStepDoIt="1"/> + <process name="G4MuIonisation" ordAtRestDoIt="-1" ordAlongSteptDoIt="2" + ordPostStepDoIt="2"/> + </particle> + ... + </processes> + + <physics> <!-- Physics constructors --> + <construct name="G4EmStandardPhysics"/> + <construct name="HadronPhysicsQGSP"/> + ... + </physics> + + </physicslist> +</geant4_setup> +\end{code} +\begin{figure}[h] +\caption{XML snippet showing the configuration of a physics list.} +\label{fig:ddg4-setup-xml-physicslist} +\end{figure} + +\begin{itemize}\itemcompact +\item To base all these constructs on an already existing predefined Geant4 physics list + use the \tts{<extends>} tag with the attribute containing the name of the physics list + as shown in line 4. +\item To trigger a call to a \bold{particle constructors} (line 7-14), use the \tts{<particles>} section + and define the Geant4 particle constructor to be called by name. To trigger a call to +\item \bold{physics process constructors}, as shown in line 19-30, + Define for each particle matching the name pattern (regular expression!) and the + default cut value for the corresponding processes. The attributes ordXXXX correspond + to the arguments of the Geant4 call \\ + \tts{G4ProcessManager::AddProcess(process,ordAtRestDoIt, ordAlongSteptDoIt,ordPostStepDoIt);} + The processes themself are created using the ROOT plugin mechanism. + To trigger a call to +\item \bold{physics constructors}, as shown in line 34-35, use the \tts{<physics>} section. +\end{itemize} +If only a predefined physics list is used, which probably already satisfies very many use cases, +all these section collapse to: +\begin{code} +<geant4_setup> + <physicslist name="Geant4PhysicsList/MyPhysics.0"> + <extends name="QGSP_BERT"/> <!-- Geant4 basic Physics list --> + </physicslist> +</geant4_setup> +\end{code} + +%============================================================================= +\subsubsection{Setup of Global Geant4 Actions} +\label{sec:ddg4-setup-xml-geant4-actions} +%============================================================================= + +\noindent +Global actions must be defined in the \tts{<actions>} section as shown in the following snippet: +\begin{code} +<geant4_setup> + <actions> + <action name="Geant4TestRunAction/RunInit"> + <properties Property_int="12345" + Property_double="-5e15" + Property_string="Startrun: Hello_2"/> + </action> + <action name="Geant4TestEventAction/UserEvent_2" + Property_int="1234" + Property_double="5e15" + Property_string="Hello_2" /> + </actions> +</geant4_setup> +\end{code} +The default properties of \bold{every} \tts{Geant4Action} object are: +\begin{unnumberedcode} +Name [string] Action name +OutputLevel [int] Flag to customize the level of printout +Control [boolean] Flag if the UI messenger should be installed. +\end{unnumberedcode} +The \tts{name} attribute of an action child is a qualified name: The first part +denotes the type of the plugin (i.e. its class), the second part the name of the instance. +Within one collection the instance \tts{name} must be unique. +Properties of Geant4Actions are set by placing them as attributes into the +\tts{<properties>} section. + +%============================================================================= +\subsubsection{Setup of Geant4 Filters} +\label{sec:ddg4-setup-xml-geant4-filters} +%============================================================================= +\noindent +Filters are special actions called by \tts{Geant4Sensitive}s. +Filters may be global or anonymous i.e. reusable by several sensitive detector +sequences as illustrated in Section~\ref{sec:ddg4-setup-xml-geant4-sequences}. +The setup is analogous to the setup of global actions: +\begin{code} + <filters> + <filter name="GeantinoRejectFilter/GeantinoRejector"/> + <filter name="ParticleRejectFilter/OpticalPhotonRejector"> + <properties particle="opticalphoton"/> + </filter> + <filter name="ParticleSelectFilter/OpticalPhotonSelector"> + <properties particle="opticalphoton"/> + </filter> + <filter name="EnergyDepositMinimumCut"> + <properties Cut="10*MeV"/> + </filter> + <!-- ... next global filter ... --> + </filters> +\end{code} +Global filters are accessible from the \tts{Geant4Kernel} object. + +%============================================================================= +\subsubsection{Geant4 Action Sequences} +\label{sec:ddg4-setup-xml-geant4-sequences} +%============================================================================= + +\noindent +\tts{Geant4 Action Sequences} by definition are \tts{Geant4Action} objects. +Hence, they share the setup mechanism with properties etc. For the setup +mechanism two different types of sequences are known to \DDG: +{\it{Action sequences}} and {\it{Sensitive detector sequences}}. Bot are declared in +the \tts{sequences} section: +\begin{code} +<geant4_setup> + <sequences> + <sequence name="Geant4EventActionSequence/EventAction"> <!-- Sequence "EventAction" of type + "Geant4EventActionSequence" --> + <action name="Geant4TestEventAction/UserEvent_1"> <!-- Anonymous action --> + <properties Property_int="01234" <!-- Properties go inline --> + Property_double="1e11" + Property_string="'Hello_1'"/> + </action> + <action name="UserEvent_2"/> <!-- Global action defined in "actions" --> + <!-- Only the name is referenced here --> + <action name="Geant4Output2ROOT/RootOutput"> <!-- ROOT I/O action --> + <properties Output="simple.root"/> <!-- Output file property --> + </action> + <action name="Geant4Output2LCIO/LCIOOutput"> <!-- LCIO output action --> + <properties Output="simple.lcio"/> <!-- Output file property --> + </action> + </sequence> + + + <sequence sd="SiTrackerBarrel" type="Geant4SensDetActionSequence"> + <filter name="GeantinoRejector"/> + <filter name="EnergyDepositMinimumCut"/> + <action name="Geant4SimpleTrackerAction/SiTrackerBarrelHandler"/> + </sequence> + <sequence sd="SiTrackerEndcap" type="Geant4SensDetActionSequence"> + <filter name="GeantinoRejector"/> + <filter name="EnergyDepositMinimumCut"/> + <action name="Geant4SimpleTrackerAction/SiTrackerEndcapHandler"/> + </sequence> + <!-- ... next sequence ... --> + </sequences> +</geant4_setup> +\end{code} +Here firstly the \bold{EventAction} sequence is defined with its members. +Secondly a sensitive detector sequence is defined for the subdetector +\tts{SiTrackerBarrel} of type \tts{Geant4SensDetActionSequence}. +The sequence uses two filters: \tts{GeantinoRejector} to not generate hits +from geantinos and \tts{EnergyDepositMinimumCut} to enforce a minimal energy deposit. +These filters are global i.e. they may be applied by many subdetectors. +The setup of global filters is described in +Section~\ref{sec:ddg4-setup-xml-geant4-filters}. +Finally the action \tts{SiTrackerEndcapHandler} of type \tts{Geant4SimpleTrackerAction} +is chained, which collects the deposited energy and +creates a collection of hits. The \tts{Geant4SimpleTrackerAction} is a template +callback to illustrate the usage of sensitive elements in \DDG. +The resulting hit collection of these handlers by default have the same name as the +object instance name. +Analogous below the sensitive detector sequence for the subdetector +\tts{SiTrackerEndcap} is shown, which reuses the same filter actions, but will build its own +hit collection. + +\noindent +\bold{Please note:} +\begin{itemize}\itemcompact +\item \bold{It was already mentioned, but once again}: Event-, run-, generator-, tracking-, + stepping- and stacking actions sequences have predefined names! + These names are fixed and part of the \bold{common knowledge}, they cannot be altered. + Please refer to + Section~\ref{sec:ddg4-user-manual-implementation-geant4action-sequences} + for the names of the global action sequences. +\item the sensitive detector sequences are matched by the attribute \tts{sd} to the + subdetectors created with the \DDhep detector description package. Values must match! +\item In the event that several xml files are parsed it is absolutely vital that + the \tts{<actions>} section is interpreted \bold{before} the \tts{sequences}. +\item For each XML file several \tts{<sequences>} are allowed. +\noindent +\end{itemize} + +%============================================================================= +\subsubsection{Setup of Geant4 Sensitive Detectors} +\label{sec:ddg4-setup-xml-geant4-sensitive detectors} +%============================================================================= +\begin{code} + <geant4_setup> + <sensitive_detectors> + <sd name="SiTrackerBarrel" + type="Geant4SensDet" + ecut="10.0*MeV" + verbose="true" + hit_aggregation="position"> + </sd> + <!-- ... next sensitive detector ... --> + </sensitive_detectors> + </geant4_setup> +\end{code} + + + +%============================================================================= +\subsubsection{Miscellaneous Setup of Geant4 Objects} +\label{sec:ddg4-setup-xml-geant4-objects} +%============================================================================= + +\noindent +This section is used for the flexible setup of auxiliary objects such as the +electromagnetic fields used in Geant4: +\begin{code} + <geant4_setup> + <properties> + <attributes name="geant4_field" + id="0" + type="Geant4FieldSetup" + object="GlobalSolenoid" + global="true" + min_chord_step="0.01*mm" + delta_chord="0.25*mm" + delta_intersection="1e-05*mm" + delta_one_step="0.001*mm" + eps_min="5e-05*mm" + eps_max="0.001*mm" + stepper="HelixSimpleRunge" + equation="Mag_UsualEqRhs"> + </attributes> + ... + </properties> + </geant4_setup> +\end{code} +Important are the tags \tts{type} and \tts{object}, which are used to firstly +define the plugin to be called and secondly define the object from the \DDhep +description to be configured for the use within Geant4. + +%============================================================================= +\subsubsection{Setup of Geant4 Phases} +\label{sec:ddg4-setup-xml-geant4-phases} +%============================================================================= + +\noindent +Phases are configured as shown below. +However, the use is \bold{discouraged}, +since it is not yet clear if there are appropriate use cases! +\begin{code} + <phases> + <phase type="RunAction/begin"> + <action name="RunInit"/> + <action name="Geant4TestRunAction/UserRunInit"> + <properties Property_int="1234" + Property_double="5e15" + Property_string="'Hello_2'"/> + </action> + </phase> + <phase type="EventAction/begin"> + <action name="UserEvent_2"/> + </phase> + <phase type="EventAction/end"> + <action name="UserEvent_2"/> + </phase> + ... + </phases> +\end{code} + +\newpage +%============================================================================= +\subsection{Setting up DDG4 using ROOT-CINT} +\label{sec:ddg4-implementation-setup-root-cint} +%============================================================================= + +\noindent +The setup of \DDG directly from the the ROOT interpreter using the AClick +mechanism is very simple, but mainly meant for purists (like me ;-)), +since it is nearly equivalent to the explicit setup within a \tts{C++} +main program. +The following code section shows how to do it. For explanation the code +segment is discussed below line by line. +\begin{code} +#include "DDG4/Geant4Config.h" +#include "DDG4/Geant4TestActions.h" +#include "DDG4/Geant4TrackHandler.h" +#include <iostream> + +using namespace std; +using namespace DD4hep; +using namespace DD4hep::Simulation; +using namespace DD4hep::Simulation::Test; +using namespace DD4hep::Simulation::Setup; + +#if defined(__MAKECINT__) +#pragma link C++ class Geant4RunActionSequence; +#pragma link C++ class Geant4EventActionSequence; +#pragma link C++ class Geant4SteppingActionSequence; +#pragma link C++ class Geant4StackingActionSequence; +#pragma link C++ class Geant4GeneratorActionSequence; +#pragma link C++ class Geant4Action; +#pragma link C++ class Geant4Kernel; +#endif + +SensitiveSeq::handled_type* setupDetector(Kernel& kernel, const std::string& name) { + SensitiveSeq sd = SensitiveSeq(kernel,name); + Sensitive sens = Sensitive(kernel,"Geant4TestSensitive/"+name+"Handler",name); + sd->adopt(sens); + sens = Sensitive(kernel,"Geant4TestSensitive/"+name+"Monitor",name); + sd->adopt(sens); + return sd; +} + +void exampleAClick() { + Geant4Kernel& kernel = Geant4Kernel::instance(LCDD::getInstance()); + kernel.loadGeometry("file:../DD4hep.trunk/DDExamples/CLICSiD/compact/compact.xml"); + kernel.loadXML("DDG4_field.xml"); + + GenAction gun(kernel,"Geant4ParticleGun/Gun"); + gun["energy"] = 0.5*GeV; // Set properties + gun["particle"] = "e-"; + gun["multiplicity"] = 1; + kernel.generatorAction().adopt(gun); + + Action run_init(kernel,"Geant4TestRunAction/RunInit"); + run_init["Property_int"] = 12345; + kernel.runAction().callAtBegin (run_init.get(),&Geant4TestRunAction::begin); + kernel.eventAction().callAtBegin(run_init.get(),&Geant4TestRunAction::beginEvent); + kernel.eventAction().callAtEnd (run_init.get(),&Geant4TestRunAction::endEvent); + + Action evt_1(kernel,"Geant4TestEventAction/UserEvent_1"); + evt_1["Property_int"] = 12345; // Set properties + evt_1["Property_string"] = "Events"; + kernel.eventAction().adopt(evt_1); + + EventAction evt_2(kernel,"Geant4TestEventAction/UserEvent_2"); + kernel.eventAction().adopt(evt_2); + + kernel.runAction().callAtBegin(evt_2.get(),&Geant4TestEventAction::begin); + kernel.runAction().callAtEnd (evt_2.get(),&Geant4TestEventAction::end); + + setupDetector(kernel,"SiVertexBarrel"); + setupDetector(kernel,"SiVertexEndcap"); + // .... more subdetectors here ..... + setupDetector(kernel,"LumiCal"); + setupDetector(kernel,"BeamCal"); + + kernel.configure(); + kernel.initialize(); + kernel.run(); + std::cout << "Successfully executed application .... " << std::endl; + kernel.terminate(); +} +\end{code} + +\noindent +\begin{tabular} {l||p{0cm}} +\docline{Line}{} +\docline{1}{The header file \tts{Geant4Config.h} contains a set of wrapper + classes to easy the creation of objects using the plugin mechanism and setting + properties to \tts{Geant4Action} objects. These helpers and the corresponding + functionality are not included in the wrapped classes themselves to not + clutter the code with stuff only used for the setup. + All contained objects are in the namespace \tts{DD4hep::Simulation::Setup}}. +\docline{6-10}{Save yourself specifying all the namespaces objects are in....} +\docline{13-19}{CINT processing pragmas. + Classes defined here will be available at the ROOT prompt + after this AClick is loaded.} +\docline{22-29}{Sampler to fill the sensitive detector sequences for each + subdetector with two entries: a handler and a monitor action. + Please note, that this here is example code and in real life specialized actions + will have to be provided for each subdetector.} +\docline{31}{Let's go for it. here the entry point starts....} +\docline{32}{Create the \tts{Geant4Kernel} object.} +\docline{33}{Load the geometry into \DDhep.} +\docline{34}{Redefine the setup of the sensitive detectors.} +\docline{36-40}{Create the generator action of type \tts{Geant4ParticleGun} with name + \tts{Gun}, set non-default properties and activate the configured object + by attaching it to the \tts{Geant4Kernel}.} +\docline{42-46}{Create a user defined begin-of-run action callback, set the properties + and attach it to the begin of run calls. To collect statistics extra member functions + are registered to be called at the beginning and the end of each event.} +\docline{48-51}{Create a user defined event action routine, set its properties + and attach it to the event action sequence.} +\docline{53-54}{Create a second event action and register it to the event action sequence. + This action will be called after the previously created action.} +\docline{56-57}{For this event action we want to receive callbacks at start- + and end-of-run to produce additional summary output.} +\docline{59-63}{Call the sampler routine to attach test actions to the subdetectors defined.} +\docline{65-66}{Configure, initialize and run the Geant4 application. + Most of the Geant4 actions will only be created here and the action sequences + created before will be attached now.} +\docline{69}{Terminate the Geant4 application and exit.} +\end{tabular} + +\newpage +\noindent +CINT currently cannot handle pointers to member functions~\footnote{This may change +in the future once ROOT uses \tts{clang} and \tts{cling} as the interpreting engine.}. +Hence the above AClick only works in compiled mode. To invoke the compilation the following +action is necessary from the ROOT prompt: + + +\begin{code} +$> root.exe + ******************************************* + * * + * W E L C O M E to R O O T * + * * + * Version 5.34/10 29 August 2013 * + * * + * You are welcome to visit our Web site * + * http://root.cern.ch * + * * + ******************************************* + +ROOT 5.34/10 (heads/v5-34-00-patches@v5-34-10-5-g0e8bac8, Sep 04 2013, 11:52:19 on linux) + +CINT/ROOT C/C++ Interpreter version 5.18.00, July 2, 2010 +Type ? for help. Commands must be C++ statements. +Enclose multiple statements between { }. +root [0] .X initAClick.C +.... Setting up the CINT include pathes and the link statements. + +root [1] .L ../DD4hep.trunk/DDG4/examples/exampleAClick.C+ +Info in <TUnixSystem::ACLiC>: creating shared library ....exampleAClick_C.so +.... some Cint warnings concerning member function pointers ..... + +root [2] exampleAClick() +.... and it starts ... +\end{code} + +\noindent +The above scripts are present in the DDG4/example directory located in svn. +The initialization script \tts{initAClick.C} may require customization +to cope with the installation paths. + +%============================================================================= +\subsection{Setting up DDG4 using Python} +\label{sec:ddg4-implementation-setup-python} +%============================================================================= + +\noindent +Given the reflection interface of ROOT, the setup of the simulation interface +using DD4hep is of course also possible using the python interpreted language. +In the following code example the setup of Geant4 using the \tts{ClicSid} +example is shown using python~\footnote{For comparison, the same example was +used to illustrate the setup using XML files.}. + +\begin{code} +import DDG4 +from SystemOfUnits import * + +""" + + DD4hep example setup using the python configuration + + @author M.Frank + @version 1.0 + +""" +def run(): + kernel = DDG4.Kernel() + kernel.loadGeometry("file:../DD4hep.trunk/DDExamples/CLICSiD/compact/compact.xml") + kernel.loadXML("DDG4_field.xml") + + lcdd = kernel.lcdd() + print '+++ List of sensitive detectors:' + for i in lcdd.detectors(): + o = DDG4.DetElement(i.second) + sd = lcdd.sensitiveDetector(o.name()) + if sd.isValid(): + print '+++ %-32s type:%s'%(o.name(), sd.type(), ) + + # Configure Run actions + run1 = DDG4.RunAction(kernel,'Geant4TestRunAction/RunInit') + run1.Property_int = 12345 + run1.Property_double = -5e15*keV + run1.Property_string = 'Startrun: Hello_2' + print run1.Property_string, run1.Property_double, run1.Property_int + run1.enableUI() + kernel.registerGlobalAction(run1) + kernel.runAction().add(run1) + + # Configure Event actions + evt2 = DDG4.EventAction(kernel,'Geant4TestEventAction/UserEvent_2') + evt2.Property_int = 123454321 + evt2.Property_double = 5e15*GeV + evt2.Property_string = 'Hello_2 from the python setup' + evt2.enableUI() + kernel.registerGlobalAction(evt2) + + evt1 = DDG4.EventAction(kernel,'Geant4TestEventAction/UserEvent_1') + evt1.Property_int=01234 + evt1.Property_double=1e11 + evt1.Property_string='Hello_1' + evt1.enableUI() + + kernel.eventAction().add(evt1) + kernel.eventAction().add(evt2) + + # Configure I/O + evt_root = DDG4.EventAction(kernel,'Geant4Output2ROOT/RootOutput') + evt_root.Control = True + evt_root.Output = "simple.root" + evt_root.enableUI() + + evt_lcio = DDG4.EventAction(kernel,'Geant4Output2LCIO/LcioOutput') + evt_lcio.Output = "simple_lcio" + evt_lcio.enableUI() + + kernel.eventAction().add(evt_root) + kernel.eventAction().add(evt_lcio) + + # Setup particle gun + gun = DDG4.GeneratorAction(kernel,"Geant4ParticleGun/Gun") + gun.energy = 0.5*GeV + gun.particle = 'e-' + gun.multiplicity = 1 + gun.enableUI() + kernel.generatorAction().add(gun) + + # Setup global filters for use in sensitive detectors + f1 = DDG4.Filter(kernel,'GeantinoRejectFilter/GeantinoRejector') + f2 = DDG4.Filter(kernel,'ParticleRejectFilter/OpticalPhotonRejector') + f2.particle = 'opticalphoton' + f3 = DDG4.Filter(kernel,'ParticleSelectFilter/OpticalPhotonSelector') + f3.particle = 'opticalphoton' + f4 = DDG4.Filter(kernel,'EnergyDepositMinimumCut') + f4.Cut = 10*MeV + f4.enableUI() + kernel.registerGlobalFilter(f1) + kernel.registerGlobalFilter(f2) + kernel.registerGlobalFilter(f3) + kernel.registerGlobalFilter(f4) + + # First the tracking detectors + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/SiVertexBarrel') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleTrackerAction/SiVertexBarrelHandler','SiVertexBarrel') + seq.add(act) + seq.add(f1) + seq.add(f4) + act.add(f1) + + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/SiVertexEndcap') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleTrackerAction/SiVertexEndcapHandler','SiVertexEndcap') + seq.add(act) + seq.add(f1) + seq.add(f4) + + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/SiTrackerBarrel') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleTrackerAction/SiTrackerBarrelHandler','SiTrackerBarrel') + seq.add(act) + seq.add(f1) + seq.add(f4) + + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/SiTrackerEndcap') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleTrackerAction/SiTrackerEndcapHandler','SiTrackerEndcap') + seq.add(act) + + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/SiTrackerForward') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleTrackerAction/SiTrackerForwardHandler','SiTrackerForward') + seq.add(act) + + # Now the calorimeters + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/EcalBarrel') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/EcalBarrelHandler','EcalBarrel') + seq.add(act) + + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/EcalEndcap') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/EcalEndCapHandler','EcalEndcap') + seq.add(act) + + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/HcalBarrel') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/HcalBarrelHandler','HcalBarrel') + act.adoptFilter(kernel.globalFilter('OpticalPhotonRejector')) + seq.add(act) + + act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/HcalOpticalBarrelHandler','HcalBarrel') + act.adoptFilter(kernel.globalFilter('OpticalPhotonSelector')) + seq.add(act) + + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/HcalEndcap') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/HcalEndcapHandler','HcalEndcap') + seq.add(act) + + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/HcalPlug') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/HcalPlugHandler','HcalPlug') + seq.add(act) + + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/MuonBarrel') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/MuonBarrelHandler','MuonBarrel') + seq.add(act) + + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/MuonEndcap') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/MuonEndcapHandler','MuonEndcap') + seq.add(act) + + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/LumiCal') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/LumiCalHandler','LumiCal') + seq.add(act) + + seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/BeamCal') + act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/BeamCalHandler','BeamCal') + seq.add(act) + + # Now build the physics list: + phys = kernel.physicsList() + phys.extends = 'FTFP_BERT' + #phys.transportation = True + phys.decays = True + phys.enableUI() + + ph = DDG4.PhysicsList(kernel,'Geant4PhysicsList/Myphysics') + ph.addParticleConstructor('G4BosonConstructor') + ph.addParticleConstructor('G4LeptonConstructor') + ph.addParticleProcess('e[+-]','G4eMultipleScattering',-1,1,1) + ph.addPhysicsConstructor('G4OpticalPhysics') + ph.enableUI() + phys.add(ph) + + phys.dump() + + kernel.configure() + kernel.initialize() + kernel.run() + kernel.terminate() + +if __name__ == "__main__": + run() + +\end{code} + +\newpage +%============================================================================= +\subsection{A Simple Example} +\label{sec:ddg4-implementation-simple-example} +%============================================================================= +\noindent +Bla-bal. + +\newpage + diff --git a/doc/LaTex/DDG4Manual.tex b/doc/LaTex/DDG4Manual.tex index 83a9c692c540ba872b68fd46c797f0f4e970ea68..fa718202bac7ee384ff754aa8267ba8e2dfc4356 100644 --- a/doc/LaTex/DDG4Manual.tex +++ b/doc/LaTex/DDG4Manual.tex @@ -79,2334 +79,12 @@ version & Date & Author \\[0.2cm] \hline \pagenumbering{arabic} \setcounter{page}{1} -%============================================================================= -\section{Introduction} -\label{sec:ddg4-user-manual-introduction} -%============================================================================= -\noindent -This manual should introduce to the DDG4 framework. -One goal of \DDG is to easily configure the simulation applications -capable of simulating the physics response of detector configurations -as they are used for example in high energy physics experiments. -In such simulation programs the user normally has to define the -experimental setup in terms of its geometry and in terms of its -active elements which sample the detector response. - -\noindent -The goal of \DDG is to generalize the configuration of a simulation -application to a degree, which does not force users to write code -to test a detector design. At the same time it should of course -be feasible to supply specialized user written modules which are supposed -to seamlessly operate together with standard modules supplied by the toolkit. -Detector-simulation depends strongly on the use of an underlying simulation -toolkit, the most prominent candidate nowadays being Geant4~\cite{bib:geant4}. -\DDhep supports simulation activities with Geant4 providing -an automatic translation mechanism between geometry representations. -The simulation response in the active elements of the detector -is strongly influenced by the technical -choices and precise simulations depends on the very specific detection techniques. - -\noindent -Similar to the aim of \DDhep~\cite{bib:DD4hep}, -where with time a standard palette of detector -components developed by users should become part of the toolkit, -\DDG also hopes to provide a standard palette of components used -to support simulation activities for detector layouts -where detector designers may base the simulation of a planned experiment -on these predefined components for initial design and optimization -studies. The longterm vision is to construct simulation applications -writing only new components not yet present i.e. the main work will be to -select the appropriate components from the palette and connect them -to a functional program. - -\noindent -This is not a manual to Geant4 nor the basic infrastructure of \DDhep. -It is assumed that this knowledge is present and the typical glossary -is known. - -%============================================================================= -\section{The Geant4 User Interface} -\label{sec:ddg4-user-manual-geant4-interface} -%============================================================================= - -\noindent -The Geant4 simulation toolkit~\cite{bib:geant4} implements a very complex -machinery to simulate the energy deposition of particles traversing materials. -To ease its usage for the clients and to shield clients from the complex -internals when actually implementing a simulation applications for a -given detector design, it provides several user hooks -as shown in Figure~\ref{fig:ddg4-g4runmanager-anatomy}. Each of these hooks -serves a well specialized purpose, but unfortunately also leads to very -specialized applications. One aim of \DDG is to formalize these user -actions so that the invocation at the appropriate time may be purely -data driven. -\begin{figure}[h] - \begin{center} - \includegraphics[height=70mm] {DDG4-G4RunManagerAnatomy.png} - \caption{The various user hooks provided by Geant4. Not shown here - is the callback system interfacing to the active elements - of the detector design.} - \label{fig:ddg4-g4runmanager-anatomy} - \end{center} -\end{figure} - -\noindent -In detail the following object-hooks allow the client to define user provided actions: -\begin{itemize}\itemcompact -\item The \bold{User Physics List} allows the client to customize and define - the underlying physics process(es) which define the particle interactions - inside the detector defined with the geometry description. - These interactions define the detector response in terms of - energy depositions. -\item The \bold{Run Action} is called once at the start and end of a run. - i.e. a series of generated events. These two callbacks - allow clients to define run-dependent actions such as statistics - summaries etc. -\item The \bold{Primary Generator Action} is called for every event. - During the callback all particles are created which form the - microscopic kinematic action of the particle collision. - This input may either origin directly from an event generator program - or come from file. -\item The \bold{Event Action} is called once at the start and the end of each event. - It is typically used for a simple analysis of the processed event. - If the simulated data should be written to some persistent medium, - the call at the end of the event processing is the appropriate place. -\item The \bold{Tracking Action} -\item The \bold{Stepping Action} -\item The \bold{Stacking Action} -\end{itemize} -\noindent -Geant4 provides all callbacks with the necessary information in the form of -appropriate arguments. - -\noindent -Besides the callback system, Geant4 provides callbacks whenever a particle -traverses a sensitive volume. These callbacks are called -- similar to event actions - once at the start and the end of the event, -but in addition, if either the energy deposit of a particle in the -sensitive volume exceeds some threshold. The callbacks are formalized within -the base class \tts{G4VSensitiveDetector}. - -%============================================================================= -\section{DDG4 Implementation} -\label{sec:ddg4-user-manual-implementation} -%============================================================================= - -\noindent -A basic design criteria of the a \DDG simulation application was to -process any user defined hook provided by Geant4 as a series of algorithmic -procedures, which could be implemented either using inheritance or by -a callback mechanism registering functions fulfilling a given signature. -Such sequences are provided for all actions mentioned in the list in -Section~\ref{sec:ddg4-user-manual-geant4-interface} as well as for -the callbacks to sensitive detectors. - -\noindent -The callback mechanism was introduced to allow for weak coupling between -the various actions. For example could an action performing monitoring -using histograms at the event level initialize or reset its histograms -at the start/end of each run. To do so, clearly a callback at the -start/end of a run would be necessary. - -\noindent -In the following sections a flexible and extensible interface to hooks -of Geant4 is discussed starting with the description of the basic -components \tts{Geant4Kernel} and \tts{Geant4Action} followed by the -implementation of the relevant specializations. -The specializations exposed are sequences of such actions, -which also call registered objects. -In later section the configuration and the combination of these components -forming a functional simulation application is presented. - -%============================================================================= -\subsection{The Application Core Object: Geant4Kernel} -\label{sec:ddg4-user-manual-implementation-geant4kernel} -%============================================================================= - -\noindent -The kernel object is the central context of a \DDG simulation application and -gives all clients access to the user hooks (see Figure~\ref{fig:ddg4-geant4-kernel}). -All Geant4 callback structures are exposed so that clients can easily -objects implementing the required interface or register callbacks with the -correct signature. Each of these action sequences is connected to an instance -of a Geant4 provided callback structure as it is shown in -Figure~\ref{fig:ddg4-g4runmanager-anatomy}. -\begin{figure}[h] - \begin{center} - \includegraphics[height=65mm] {DDG4-Geant4Kernel.png} - \caption{The main application object gives access to all sequencing actions - in a \DDG4 application. Sequence actions are only container of user actions - calling one user action after the other. Optionally single callbacks may - be registered to a user action.} - \label{fig:ddg4-geant4-kernel} - \end{center} -\end{figure} - -%============================================================================= -\subsection{Action Sequences} -\label{sec:ddg4-user-manual-implementation-geant4action-sequences} -%============================================================================= - -\noindent -As shown in - -%============================================================================= -\subsection{The Base Class of DDG4 Actions: Geant4Action} -\label{sec:ddg4-user-manual-implementation-geant4action-base} -%============================================================================= - -\noindent -The class \tts{Geant4Action} is a common component interface providing -the basic interface to the framework to -\begin{itemize}\itemcompact -\item configure the component using a property mechanism -\item provide an appropriate interface to Geant4 interactivity. The interactivity - included a generic way to change and access properties from the Geant4 UI - prompt as well as executing registered commands. -\item As shown in Figure~\ref{fig:ddg4-implementation-geant4-action}, the - base class also provides to its sub-class a reference to the \tts{Geant4Kernel} - objects through the \tts{Geant4Context}. -\end{itemize} -The \tts{Geant4Action} is a named entity and can be uniquely identified within -a sequence attached to one Geant4 user callback. -%============================================================================= -\begin{figure}[h] - \begin{center} - \includegraphics[height=30mm] {DDG4-Geant4Action.png} - \caption{The design of the common base class \tts{Geant4Action}.} - \label{fig:ddg4-implementation-geant4-action} - \end{center} -\end{figure} - -\noindent -\DDG knows two types of actions: global actions and anonymous actions. -Global actions are accessible externally from the \tts{Geant4Kernel} instance. -Global actions are also re-usable and hence may be contribute to several -action sequences (see the following chapters for details). Global actions -are uniquely identified by their name. -Anonymous actions are known only within one sequence and normally -are not shared between sequences. - -%============================================================================= -\subsubsection{The Properties of \bold{Geant4Action} Instances} -\label{sec:ddg4-implementation-geant4-action-properties} -%============================================================================= - -\noindent -Nearly any subclass of a \tts{Geant4Action} needs a flexible configuration -in order to be reused, modified etc. The implementation of the mechanism -uses a very flexible value conversion mechanism using \tts{boost::spirit}, -which support also conversions between unrelated types provided a dictionary -is present. - -\noindent -Properties are supposed to be member variables of a given action object. -To publish a property it needs to be declared in the constructor as shown here: -\begin{unnumberedcode} - declareProperty("OutputLevel", m_outputLevel = INFO); - declareProperty("Control", m_needsControl = false); -\end{unnumberedcode} -The internal setup of the \tts{Geant4Action} objects then ensure that -all declared properties will be set after the object construction to the -values set in the setup file. - -\noindent -\bold{Note:} Because the values can only be set \bold{after} the object -was constructed, the actual values may not be used in the constructor -of any base or sub-class. - -%============================================================================= -\subsection{Geant4 Action Sequences} -\label{sec:ddg4-user-manual-implementation-geant4action-sequences} -%============================================================================= - -\noindent -All Geant4 user hooks are realized as action sequences. As shown in -Figure~\ref{fig:ddg4-geant4-kernel} these sequences are accessible to the user, -who may attach specialized actions to the different action sequences. This -allows a flexible handing of specialized user actions e.g. to dynamically -add monitoring actions filling histograms or to implement alternative hit -creation mechanism in a sensitive detector for detailed detector studies. -Figure~\ref{fig:ddg4-implementation-sequence-calls} shows the schematic -call structure of an example {\tt{Geant4TrackingActionSequence}}:\\ -\begin{figure}[h] - \begin{center} - \includegraphics[width=150mm] {DDG4-TrackingActionCalls.png} - \caption{The design of the tracking action sequence. Specialized - tracking action objects inherit from the \tts{Geant4TrackingAction} - object and must be attached to the sequence.} - \label{fig:ddg4-implementation-sequence-calls} - \end{center} -\end{figure} - -\noindent -Geant4 calls the function from the virtual interface (\tw{G4UserTrackingAction}), -which is realised by the \tw{Geant4UserTrackingAction} with the single purpose to -propagate the call to the action sequence, which then calls all registered clients -of type \tw{Geant4TrackingAction}. - -\noindent -The main action sequences have a fixed name. These are -\begin{itemize} - -\item The \bold{RunAction} attached to the \tts{G4UserRunAction}, implemented - by the \tts{Geant4RunActionSequence} class and is called at the start and the end of - every run (beamOn). Members of the \tts{Geant4RunActionSequence} are of type - \tts{Geant4RunAction} and receive the callbacks by overloading the two routines: -\begin{unnumberedcode} -/// begin-of-run callback -virtual void begin(const G4Run* run); -/// End-of-run callback -virtual void end(const G4Run* run); -\end{unnumberedcode} - or register a callback with the signature {\tts{void (T::*)(const G4Run*)}} - either to receive begin-of-run or end-or-calls using the methods: -\begin{unnumberedcode} -/// Register begin-of-run callback. Types Q and T must be polymorph! -template <typename Q, typename T> void callAtBegin(Q* p, void (T::*f)(const G4Run*)); -/// Register end-of-run callback. Types Q and T must be polymorph! -template <typename Q, typename T> void callAtEnd(Q* p, void (T::*f)(const G4Run*)); -\end{unnumberedcode} - of the \tts{Geant4RunActionSequence} from the \tts{Geant4Context} object. - - -\item The \bold{EventAction} attached to the \tts{G4UserEventAction}, implemented - by the \tts{EventActionSequence} class and is called at the start and the end of - every event. Members of the \tts{Geant4EventActionSequence} are of type - \tts{Geant4EventAction} and receive the callbacks by overloading the two routines: -\begin{unnumberedcode} -/// Begin-of-event callback -virtual void begin(const G4Event* event); -/// End-of-event callback -virtual void end(const G4Event* event); -\end{unnumberedcode} - or register a callback with the signature {\tts{void (T::*)(const G4Event*)}} - either to receive begin-of-run or end-or-calls using the methods: -\begin{unnumberedcode} -/// Register begin-of-event callback -template <typename Q, typename T> void callAtBegin(Q* p, void (T::*f)(const G4Event*)); -/// Register end-of-event callback -template <typename Q, typename T> void callAtEnd(Q* p, void (T::*f)(const G4Event*)); -\end{unnumberedcode} - of the \tts{Geant4EventActionSequence} from the \tts{Geant4Context} object. - - -\item The \bold{GeneratorAction} attached to the \tts{G4VUserPrimaryGeneratorAction}, implemented - by the \tts{Geant4GeneratorActionSequence} class and is called at the start of - every event and provided all initial tracks from the Monte-Carlo generator. - Members of the \tts{Geant4GeneratorActionSequence} are of type - \tts{Geant4EventAction} and receive the callbacks by overloading the member function: -\begin{unnumberedcode} -/// Callback to generate primary particles -virtual void operator()(G4Event* event); -\end{unnumberedcode} - or register a callback with the signature {\tts{void (T::*)(G4Event*)}} - to receive calls using the method: -\begin{unnumberedcode} -/// Register primary particle generation callback. -template <typename Q, typename T> void call(Q* p, void (T::*f)(G4Event*)); -\end{unnumberedcode} - of the \tts{Geant4GeneratorActionSequence} from the \tts{Geant4Context} object. - -\end{itemize} -\begin{figure}[t] - \begin{center} - \includegraphics[width=160mm] {DDG4-TrackingAction.png} - \caption{The design of the tracking action sequence. Specialized - tracking action objects inherit from the \tts{Geant4TrackingAction} - object and must be attached to the sequence.} - \label{fig:ddg4-implementation-tracking-action} - \end{center} -\end{figure} - -\begin{itemize} -\item The \bold{TrackingAction} attached to the \tts{G4UserTrackingAction}, - implemented by the \tts{Geant4-} \tts{Tracking\-Action\-Sequence} class - and is called at the start and the end of tracking one single particle - trace through the material of the detector. - Members of the \tts{Geant4\-Tracking\-ActionSequence} are of type - \tts{Geant4TrackingAction} and receive the callbacks by overloading the member function: -\begin{unnumberedcode} -/// Pre-tracking action callback -virtual void begin(const G4Track* trk); -/// Post-tracking action callback -virtual void end(const G4Track* trk); -\end{unnumberedcode} - or register a callback with the signature {\tts{void (T::*)(const G4Step*, G4SteppingManager*)}} - to receive calls using the method: -\begin{unnumberedcode} -/// Register Pre-track action callback -template <typename Q, typename T> void callAtBegin(Q* p, void (T::*f)(const G4Track*)); -/// Register Post-track action callback -template <typename Q, typename T> void callAtEnd(Q* p, void (T::*f)(const G4Track*)); -\end{unnumberedcode} -Figure~\ref{fig:ddg4-implementation-tracking-action} show as an example -the design (class-diagram) of the \tts{Geant4TrackingAction}. - - -\item The \bold{SteppingAction} attached to the \tts{G4UserSteppingAction}, implemented - by the \tts{Geant4-} \tts{SteppingActionSequence} class and is called for each - step when tracking a particle. - Members of the \tts{Geant4SteppingActionSequence} are of type - \tts{Geant4SteppingAction} and receive the callbacks by overloading the member function: -\begin{unnumberedcode} -/// User stepping callback -virtual void operator()(const G4Step* step, G4SteppingManager* mgr); -\end{unnumberedcode} - or register a callback with the signature {\tts{void (T::*)(const G4Step*, G4SteppingManager*)}} - to receive calls using the method: -\begin{unnumberedcode} -/// Register stepping action callback. -template <typename Q, typename T> void call(Q* p, void (T::*f)(const G4Step*, - G4SteppingManager*)); -\end{unnumberedcode} - - -\item The \bold{StackingAction} attached to the - {\tts{G4UserStackingAction}}, implemented by the \tts{Geant4-}\\ - \tts{StackingActionSequence} class. - Members of the \tts{Geant4StackingActionSequence} are of type\\ - \detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_stacking_action.html} - {\tts{Geant4StackingAction}} and receive the callbacks by overloading the member functions: -\begin{unnumberedcode} -/// New-stage callback -virtual void newStage(); -/// Preparation callback -virtual void prepare(); -\end{unnumberedcode} - or register a callback with the signature {\tts{void (T::*)()}} - to receive calls using the method: -\begin{unnumberedcode} -/// Register begin-of-event callback. Types Q and T must be polymorph! -template <typename T> void callAtNewStage(T* p, void (T::*f)()); -/// Register end-of-event callback. Types Q and T must be polymorph! -template <typename T> void callAtPrepare(T* p, void (T::*f)()); -\end{unnumberedcode} -\end{itemize} - -\noindent -All sequence types support the method \tts{void adopt(T* member\_reference)} -to add the members. Once adopted, the sequence takes ownership and manages -the member. The design of all sequences is very similar. - -%============================================================================= -\subsection{Sensitive Detectors} -\label{sec:ddg4-user-manual-geant4sensitivedetectors} -%============================================================================= - -\noindent -Sensitive detectors are associated by the detector designers to all active -materials, which would produce a signal which can be read out. In Geant4 this concept -is realized by using a base class \tts{G4VSensitiveDetector}. -The mandate of a sensitive detector is the construction of hit objects -using information from steps along a particle track. -The \tts{G4VSensitiveDetector} receives -a callback at the begin and the end of the event processing and at each step -inside the active material whenever an energy deposition occurred. - -\begin{figure}[t] - \begin{center} - \includegraphics[height=110mm] {DDG4-Sensitive-detector.png} - \caption{The sensitive detector design. The actual energy deposits are - collected in user defined subclasses of the \tts{Geant4Sensitive}. - Here, as an example possible actions called \tts{TrackerHitCollector}, - \tts{TrackerDetailedHitCollector} and \tts{TrackerHitMonitor} are shown.} - \label{fig:ddg4-implementation-sensitive-detector} - \end{center} -\end{figure} - -\noindent -The sensitive actions do not necessarily deal only the collection of energy -deposits, but could also be used to simply monitor the performance of the -active element e.g. by producing histograms of the absolute value or the -spacial distribution of the depositions. - -\noindent -Within \DDG the concept of sensitive detectors is implemented as a -configurable action sequence of type -\detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_sens_det_action_sequence.html} -{\tts{Geant4SensDetActionSequence}} -calling members of the type -\detdesc{html/struct_d_d4hep_1_1_simulation_1_1_geant4_sensitive.html} -{\tts{Geant4Sensitive}} as shown in -Figure~\ref{fig:ddg4-implementation-sensitive-detector}. The actual processing -part of such a sensitive action is only called if the and of a set of -required filters of type \tts{Geant4Filter} is positive (see also -section~\ref{sec:ddg4-implementation-sensitive-detector-filters}). No filter -is also positive. Possible filters are e.g. particle filters, which ignore the -sensitive detector action if the particle is a \tts{geantino} or if the -energy deposit is below a given threshold. - -\noindent -Objects of type \tts{Geant4Sensitive} receive the callbacks by overloading the -member function: -\begin{unnumberedcode} - /// Method invoked at the beginning of each event. - virtual void begin(G4HCofThisEvent* hce); - /// Method invoked at the end of each event. - virtual void end(G4HCofThisEvent* hce); - /// Method for generating hit(s) using the information of G4Step object. - virtual bool process(G4Step* step, G4TouchableHistory* history); - /// Method invoked if the event was aborted. - virtual void clear(G4HCofThisEvent* hce); -\end{unnumberedcode} -or register a callback with the signature {\tts{void (T::*)(G4HCofThisEvent*)}} -respectively {\tts{void (T::*)(G4Step*, G4TouchableHistory*)}} -to receive callbacks using the methods: -\begin{unnumberedcode} - /// Register begin-of-event callback - template <typename T> void callAtBegin(T* p, void (T::*f)(G4HCofThisEvent*)); - /// Register end-of-event callback - template <typename T> void callAtEnd(T* p, void (T::*f)(G4HCofThisEvent*)); - /// Register process-hit callback - template <typename T> void callAtProcess(T* p, void (T::*f)(G4Step*, G4TouchableHistory*)); - /// Register clear callback - template <typename T> void callAtClear(T* p, void (T::*f)(G4HCofThisEvent*)); -\end{unnumberedcode} -Please refer to the Geant4 Applications manual from the Geant4 web page for -further details about the concept of sensitive detectors. - -%============================================================================= -\subsubsection{Helpers of Sensitive Detectors: The Geant4VolumeManager} -\label{sec:ddg4-user-manual-geant4volumemanager}%============================================================================= - -\noindent -Sooner or later, when a hit is created in a sensitive placed volume, the -hit must be associated with this volume. For this purpose \DDhep provides -the concept of the \tw{VolumeManager}, which identifies placed volumes uniquely -by a 64-bit identifier, the $CellID$. This mechanism allows to quickly -retrieve a given volume given the hit data containing the $CellID$. -The $CellID$ is a very compressed representation for any element in the -hierarchy of placed volumes to the sensitive volume in question. - -\noindent -During the simulation the reverse mechanism must be applied: Geant4 provides -the hierarchy of \tw{G4PhysicalVolumes} to the hit location and the local coordinates -of the hit within the sensitive volume. Hence to determine the volume identifier -is essential to store hits so that they can be later accessed and processed efficiently. -This mechanism is provided by the \tw{Geant4VolumeManager}. Clients typically do not -interact with this object, any access necessary is provided by the -\tw{Geant4Sensitive} action: -\begin{unnumberedcode} - /// Method for generating hit(s) using the information of G4Step object. - bool MySensitiveAction:process(G4Step* step,G4TouchableHistory* /*hist*/ ) { - ... - Hit* hit = new Hit(); - // *** Retrieve the cellID *** - hit->cellID = cellID(step); - ... - } -\end{unnumberedcode} -The call is realized using a member function provided by the -\tw{Geant4Sensitive} action: -\begin{unnumberedcode} - /// Returns the cellID of the sensitive volume corresponding to the step - /** The CellID is the VolumeID + the local coordinates of the sensitive area. - * Calculated by combining the VolIDS of the complete geometry path (Geant4TouchableHistory) - * from the current sensitive volume to the world volume - */ - long long int cellID(G4Step* step); -\end{unnumberedcode} - -\noindent -\bold{Note:}\\ -The \tw{Geant4VolumeManager} functionality is not for free! It requires that - - -\noindent --- match Geant4 volume with TGeo volume - -%============================================================================= -\subsubsection{DDG4 Intrinsic Sensitive Detectors} -%============================================================================= -\noindent -Currently there are two generic sensitive detectors implemented in DDG4: -\begin{itemize}\itemcompact -\item The \tw{Geant4TrackerAction}, which may be used to handle tracking devices. - This sensitive detector produces one hit for every energy deposition of Geant4 - i.e. for every callback to -\begin{unnumberedcode} - /// Method for generating hit(s) using the information of G4Step object. - virtual bool process(G4Step* step, G4TouchableHistory* history); -\end{unnumberedcode} - See the implementation file - \detdesc{html/_geant4_s_d_actions_8cpp_source.html}{DDG4/plugins/Geant4SDAction.cpp} - for details. The produced hits are of type - \detdesc{html/_geant4_data_8h_source.html}{Geant4Tracker::Hit}. - -\item The \tw{Geant4CalorimeterAction}, which may be used to handle - generic calorimeter like devices. - This sensitive detector produces at most one hit for every cell in the calorimeter. - If several tracks contribute to the energy deposit of this cell, the contributions - are added up. - See the implementation file - \detdesc{html/_geant4_s_d_actions_8cpp_source.html}{DDG4/plugins/Geant4SDAction.cpp} - for details. The produced hits are of type - \detdesc{html/_geant4_data_8h_source.html}{Geant4Calorimeter::Hit}. - propagate the MC truth information with respect to each track kept in the - particle record. -\end{itemize} - -\noindent -Both sensitive detectors use the \tw{Geant4VolumeManager} discussed in -section~\ref{sec:ddg4-user-manual-geant4volumemanager} to identify the sensitive elements. - -\noindent -\bold{PLEASE NOTE:}\\ -The above palette of generic sensitive detectors only contains two very -often used implementations. We hope, that this palette over time grows from -external contributions of other generic sensitive detectors. We would be happy -to extend this palette with other generic implementations. One example would -be the handling of the simulation response for optical detectors like RICH-Cerenkov -detectors. - -%============================================================================= -\subsubsection{Sensitive Detector Filters} -\label{sec:ddg4-implementation-sensitive-detector-filters} -%============================================================================= - -\noindent -The concept of filters allows to build more flexible sensitive detectors by -restricting the hit processing of a given instance of a sensitive action. - -\begin{itemize}\itemcompact -\item Examples would be to demand a given particle type before a sensitive action is -invoked: a sensitive action dealing with optical photons (RICH detectors, etc), -would e.g. not be interested in energy depositions of other particles. -A filter object restricting the particle type to optical photons would -be appropriate. -\item Another example would be to implement a special action instance, which would -be only called if the filter requires a minimum energy deposit. -\end{itemize} -There are plenty of possible applications, hence we would like -to introduce this feature here. - -\noindent -Filters are called by Geant4 before the -hit processing in the sensitive detectors start. The global filters -may be shared between many sensitive detectors. Alternatively filters -may be directly attached to the sensitive detector in question. -Attributes are directly passed as properties to the filter action. - -\noindent -Technically do \tw{Geant4Filter} objects inherit from the base class -\tw{Geant4Filter} (see Figure~\ref{fig:ddg4-implementation-sensitive-detector-filters}. -Any filter inherits from the common base class \tw{Geant4Filter}, then -several specializations may be configured like filters to select/reject -particles, to specify the minimal energy deposit to be processed etc. -A sensitive detector is called if the filter callback with the signature -returns a true result: -\begin{unnumberedcode} - /// Filter action. Return true if hits should be processed - virtual bool operator()(const G4Step* step) const; -\end{unnumberedcode} -\begin{figure}[h] - \begin{center} - \includegraphics[height=65mm] {DDG4-SensitiveFilterClasses.png} - \caption{The sensitive detector filters design. The shown class - diagram is actually implemented.} - \label{fig:ddg4-implementation-sensitive-detector-filters} - \end{center} -\end{figure} - -\newpage - -%============================================================================= -\subsection{The Geant4 Physics List} -\label{sec:ddg4-implementation-physics-list} -%============================================================================= -\noindent -Geant4 provides the base class \tts{G4VUserPhysicsList}, which allows users -to implement customized physics according to the studies to be made. -Any user defined physics list must provide this interface. DDG4 provides such an interface -through the ROOT plugin mechanism using the class \tts{G4VModularPhysicsList}. -The flexibility of \DDG allows for several possibilities to setup the Geant4 -physics list. Instead of explicitly coding the physics list, \DDG foresees the -usage of the plugin mechanism to instantiate the necessary calls to Geant4 in a -sequence of actions: -\begin{itemize} -\item The \bold{physics list} is realized as a sequence of actions of type - \detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_physics_list_action_sequence.html} - {\tts{Geant4PhysicsListActionSequence}}. - Members of the \detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_physics_list_action_sequence.html} - {\tts{Geant4PhysicsListActionSequence}} are of type - \detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_physics_list.html} - {\tts{Geant4PhysicsList}} and receive the callbacks by overloading - the member functions: -\begin{unnumberedcode} - /// Callback to construct the physics constructors - virtual void constructProcess(Geant4UserPhysics* interface); - /// constructParticle callback - virtual void constructParticles(Geant4UserPhysics* particle); - /// constructPhysics callback - virtual void constructPhysics(Geant4UserPhysics* physics); -\end{unnumberedcode} - or register a callback with the signature {\tts{void (T::*)(Geant4UserPhysics*)}} - to receive calls using the method: -\begin{unnumberedcode} - /// Register process construction callback t - template <typename Q, typename T> void constructProcess(Q* p, void (T::*f)(Geant4UserPhysics*)); - /// Register particle construction callback - template <typename Q, typename T> void constructParticle(Q* p, void (T::*f)(Geant4UserPhysics*)); -\end{unnumberedcode} - The argument of type \detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_user_physics.html} - {\tts{Geant4UserPhysics}} provides a basic interface to the original - \tts{G4VModular}- \tts{PhysicsList}, which allows to register physics constructors etc. - -\item In most of the cases the above approach is an overkill and often even too flexible. - Hence, alternatively, the physics list may consist of a single entry of type - \detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_physics_list.html} - {\tts{Geant4PhysicsList}}. -\end{itemize} - -\noindent -The basic implementation of the \tts{Geant4PhysicsList} supports the usage of various -\begin{itemize}\itemcompact -\item \detdesc{html/_geant4_particles_8cpp_source.html}{particle constructors}, - such as single particle constructors like - \tts{G4Gamma} or \tts{G4Proton}, or whole particle groups like - \tts{G4BosonConstructor} or \tts{G4IonConstrutor}, -\item \detdesc{html/_geant4_processes_8cpp_source.html}{physics process constructors}, - such as e.g. \tts{G4GammaConversion}, - \tts{G4PhotoElectricEffect} or\\ \tts{G4ComptonScattering}, -\item \detdesc{html/_geant4_physics_constructors_8cpp_source.html}{physics constructors} - combining particles and the corresponding - interactions, such as\\ e.g. \tts{G4OpticalPhysics}, - \tts{HadronPhysicsLHEP} or \tts{G4HadronElasticPhysics} and -\item \detdesc{html/_geant4_particles_8cpp_source.html}{predefined Geant4 physics lists}, - such as \tts{FTFP\_BERT}, - \tts{CHIPS} or \tts{QGSP\_INCLXX}. This option is triggered by the - content of the string property "extends" of the \tts{Geant4Kernel::physicsList()} action. -\end{itemize} -These constructors are internally connected to the above callbacks to register themselves. -The constructors are instantiated using the ROOT plugin mechanism. - -\noindent -The description of the above interface is only for completeness. The basic idea is, -that the physics list with its particle and physics constructors is configured -entirely data driven using the setup mechanism described in the following -chapter. However, DDG4 is not limited to the data driven approach. Specialized -physics lists may be supplied, but there should be no need. -New physics lists could always be composed by actually providing new physics -constructors and actually publishing these using the factory methods: -\begin{code} -// Framework include files -#include "DDG4/Factories.h" - -#include "My_Very_Own_Physics_Constructor.h" -DECLARE_GEANT4_PHYSICS(My_Very_Own_Physics_Constructor) -\end{code} -where \tts{My\_Very\_Own\_Physics\_Constructor} represents a sub-class of -\tts{G4VPhysicsConstructor}. - -\newpage -%============================================================================= -\subsection{The Support of the Geant4 UI: \tw{Geant4UIMessenger}} -\label{sec:ddg4-user-manual-geant4action-base} -%============================================================================= - -\noindent -The support of interactivity in Geant4 is mandatory to debug detector -setups in small steps. The Geant4 toolkit did provide for this reason -a machinery of UI commands. -\begin{figure}[h] - \begin{center} - \includegraphics[height=70mm] {DDG4-UIMessenger.png} - \caption{The design of the \tts{Geant4UIMessenger} class responsible for - the interaction between the user and the components of \DDG and Geant4.} - \label{fig:ddg4-tracking-action} - \end{center} -\end{figure} - -\noindent -The UI control is enabled, as soon as the property "Control" (boolean) is set to true. -Be default all properties of the action are exported. -Similar to the callback mechanism described above it is also feasible to -register any object callback invoking a method of a \tts{Geant4Action}-subclass. - -\noindent -The following (shortened) screen dump illustrates the usage of the -generic interface any Geant4Action offers: -\begin{unnumberedcode} -Idle> ls -Command directory path : / - Sub-directories : - /control/ UI control commands. - /units/ Available units. - /process/ Process Table control commands. - /ddg4/ Control for all named Geant4 actions - ... -Idle> cd /ddg4 -Idle> ls -... -Control for all named Geant4 actions - - Sub-directories : - /ddg4/RunInit/ Control hierarchy for Geant4 action:RunInit - /ddg4/RunAction/ Control hierarchy for Geant4 action:RunAction - /ddg4/EventAction/ Control hierarchy for Geant4 action:EventAction - /ddg4/GeneratorAction/ Control hierarchy for Geant4 action:GeneratorAction - /ddg4/LCIO1/ Control hierarchy for Geant4 action:LCIO1 - /ddg4/Smear1/ Control hierarchy for Geant4 action:Smear1 - /ddg4/PrimaryHandler/ Control hierarchy for Geant4 action:PrimaryHandler - /ddg4/TrackingAction/ Control hierarchy for Geant4 action:TrackingAction - /ddg4/SteppingAction/ Control hierarchy for Geant4 action:SteppingAction - /ddg4/ParticleHandler/ Control hierarchy for Geant4 action:ParticleHandler - /ddg4/UserParticleHandler/ Control hierarchy for Geant4 action:UserParticleHandler - ... -Idle> ls Smear1 -Command directory path : /ddg4/Smear1/ - ... - Commands : - show * Show all properties of Geant4 component:Smear1 - Control * Property item of type bool - Mask * Property item of type int - Name * Property item of type std::string - Offset * Property item of type ROOT::Math::LorentzVector<ROOT::Math::PxPyPzE4D<double> > - OutputLevel * Property item of type int - Sigma * Property item of type ROOT::Math::LorentzVector<ROOT::Math::PxPyPzE4D<double> > - name * Property item of type std::string -Idle> Smear1/show -PropertyManager: Property Control = True -PropertyManager: Property Mask = 1 -PropertyManager: Property Name = 'Smear1' -PropertyManager: Property Offset = ( -20 , -10 , -10 , 0 ) -PropertyManager: Property OutputLevel = 4 -PropertyManager: Property Sigma = ( 12 , 8 , 8 , 0 ) -PropertyManager: Property name = 'Smear1' - -Idle> Smear1/Offset (200*mm, -3*mm, 15*mm, 10*ns) -Geant4UIMessenger: +++ Smear1> Setting property value Offset = (200*mm, -3*mm, 15*mm, 10*ns) - native:( 200 , -3 , 15 , 10 ). -Idle> Smear1/show -... -PropertyManager: Property Offset = ( 200 , -3 , 15 , 10 ) - -\end{unnumberedcode} - - -\newpage -%============================================================================= -\section{Setting up DDG4} -\label{sec:ddg4-implementation-setup} -%============================================================================= - -\noindent -\DDG offers several possibilities to configure a simulation application -using -\begin{itemize}\itemcompact -\item XML files, -\item by coding a setup script loaded from the \tts{ROOT} interpreter - with the AClick mechanism. -\item by creating a setup script using \tts{python} and - \tts{ROOT}'s reflection mechanism exposed by \tts{PyROOT}. -\end{itemize} -The following subsection describe these different mechanism. An attempt was made -to match the naming conventions of all approaches where possible. - -%============================================================================= -\subsection{Setting up DDG4 using XML} -\label{sec:ddg4-implementation-setup-xml} -%============================================================================= - -\noindent -A special plugin was developed to enable the configuration of \DDG using -XML structures. These files are parsed identically to the geometry setup -in \DDhep the only difference is the name of the root-element, which for -\DDG is \tts{<geant4\_setup>}. -The following code snippet shows the basic structure of a \DDG setup file: -\begin{unnumberedcode} -<geant4_setup> - <physicslist> ,,, </physicslist> <!-- Definition of the physics list --> - <actions> ... </actions> <!-- The list of global actions --> - <phases> ... </phases> <!-- The definition of the various phases --> - <filters> ... </filters> <!-- The list of global filter actions --> - <sequences> ... </sequences> <!-- The list of defined sequences --> - <sensitive_detectors> ... </sensitive_detectors> <!-- The list of sensitive detectors --> - <properties> ... </properties> <!-- Free format option sequences --> -</geant4_setup> -\end{unnumberedcode} -To setup a \DDG4 application any number of xml setup files may be interpreted -iteratively. In the following subsections the content of these first level sub-trees will -be discussed. - -%============================================================================= -\subsubsection{Setup of the Physics List} -\label{sec:ddg4-setup-xml-physicslist} -%============================================================================= - -\noindent -The main tag to setup a physics list is \tts{<physicslist>} with the -\tts{name} attribute defining the instance of the \tts{Geant4PhysicsList} object. -An example code snippet is shown below in Figure~\ref{fig:ddg4-setup-xml-physicslist}. - -\begin{code} -<geant4_setup> - <physicslist name="Geant4PhysicsList/MyPhysics.0"> - - <extends name="QGSP_BERT"/> <!-- Geant4 basic Physics list --> - - <particles> <!-- Particle constructors --> - <construct name="G4Geantino"/> - <construct name="G4ChargedGeantino"/> - <construct name="G4Electron"/> - <construct name="G4Gamma"/> - <construct name="G4BosonConstructor"/> - <construct name="G4LeptonConstructor"/> - <construct name="G4MesonConstructor"/> - <construct name="G4BaryonConstructor"/> - ... - </particles> - - <processes> <!-- Process constructors --> - <particle name="e[+-]" cut="1*mm"> - <process name="G4eMultipleScattering" ordAtRestDoIt="-1" ordAlongSteptDoIt="1" - ordPostStepDoIt="1"/> - <process name="G4eIonisation" ordAtRestDoIt="-1" ordAlongSteptDoIt="2" - ordPostStepDoIt="2"/> - </particle> - <particle name="mu[+-]"> - <process name="G4MuMultipleScattering" ordAtRestDoIt="-1" ordAlongSteptDoIt="1" - ordPostStepDoIt="1"/> - <process name="G4MuIonisation" ordAtRestDoIt="-1" ordAlongSteptDoIt="2" - ordPostStepDoIt="2"/> - </particle> - ... - </processes> - - <physics> <!-- Physics constructors --> - <construct name="G4EmStandardPhysics"/> - <construct name="HadronPhysicsQGSP"/> - ... - </physics> - - </physicslist> -</geant4_setup> -\end{code} -\begin{figure}[h] -\caption{XML snippet showing the configuration of a physics list.} -\label{fig:ddg4-setup-xml-physicslist} -\end{figure} - -\begin{itemize}\itemcompact -\item To base all these constructs on an already existing predefined Geant4 physics list - use the \tts{<extends>} tag with the attribute containing the name of the physics list - as shown in line 4. -\item To trigger a call to a \bold{particle constructors} (line 7-14), use the \tts{<particles>} section - and define the Geant4 particle constructor to be called by name. To trigger a call to -\item \bold{physics process constructors}, as shown in line 19-30, - Define for each particle matching the name pattern (regular expression!) and the - default cut value for the corresponding processes. The attributes ordXXXX correspond - to the arguments of the Geant4 call \\ - \tts{G4ProcessManager::AddProcess(process,ordAtRestDoIt, ordAlongSteptDoIt,ordPostStepDoIt);} - The processes themself are created using the ROOT plugin mechanism. - To trigger a call to -\item \bold{physics constructors}, as shown in line 34-35, use the \tts{<physics>} section. -\end{itemize} -If only a predefined physics list is used, which probably already satisfies very many use cases, -all these section collapse to: -\begin{code} -<geant4_setup> - <physicslist name="Geant4PhysicsList/MyPhysics.0"> - <extends name="QGSP_BERT"/> <!-- Geant4 basic Physics list --> - </physicslist> -</geant4_setup> -\end{code} - -%============================================================================= -\subsubsection{Setup of Global Geant4 Actions} -\label{sec:ddg4-setup-xml-geant4-actions} -%============================================================================= - -\noindent -Global actions must be defined in the \tts{<actions>} section as shown in the following snippet: -\begin{code} -<geant4_setup> - <actions> - <action name="Geant4TestRunAction/RunInit"> - <properties Property_int="12345" - Property_double="-5e15" - Property_string="Startrun: Hello_2"/> - </action> - <action name="Geant4TestEventAction/UserEvent_2" - Property_int="1234" - Property_double="5e15" - Property_string="Hello_2" /> - </actions> -</geant4_setup> -\end{code} -The default properties of \bold{every} \tts{Geant4Action} object are: -\begin{unnumberedcode} -Name [string] Action name -OutputLevel [int] Flag to customize the level of printout -Control [boolean] Flag if the UI messenger should be installed. -\end{unnumberedcode} -The \tts{name} attribute of an action child is a qualified name: The first part -denotes the type of the plugin (i.e. its class), the second part the name of the instance. -Within one collection the instance \tts{name} must be unique. -Properties of Geant4Actions are set by placing them as attributes into the -\tts{<properties>} section. - -%============================================================================= -\subsubsection{Setup of Geant4 Filters} -\label{sec:ddg4-setup-xml-geant4-filters} -%============================================================================= -\noindent -Filters are special actions called by \tts{Geant4Sensitive}s. -Filters may be global or anonymous i.e. reusable by several sensitive detector -sequences as illustrated in Section~\ref{sec:ddg4-setup-xml-geant4-sequences}. -The setup is analogous to the setup of global actions: -\begin{code} - <filters> - <filter name="GeantinoRejectFilter/GeantinoRejector"/> - <filter name="ParticleRejectFilter/OpticalPhotonRejector"> - <properties particle="opticalphoton"/> - </filter> - <filter name="ParticleSelectFilter/OpticalPhotonSelector"> - <properties particle="opticalphoton"/> - </filter> - <filter name="EnergyDepositMinimumCut"> - <properties Cut="10*MeV"/> - </filter> - <!-- ... next global filter ... --> - </filters> -\end{code} -Global filters are accessible from the \tts{Geant4Kernel} object. - -%============================================================================= -\subsubsection{Geant4 Action Sequences} -\label{sec:ddg4-setup-xml-geant4-sequences} -%============================================================================= - -\noindent -\tts{Geant4 Action Sequences} by definition are \tts{Geant4Action} objects. -Hence, they share the setup mechanism with properties etc. For the setup -mechanism two different types of sequences are known to \DDG: -{\it{Action sequences}} and {\it{Sensitive detector sequences}}. Bot are declared in -the \tts{sequences} section: -\begin{code} -<geant4_setup> - <sequences> - <sequence name="Geant4EventActionSequence/EventAction"> <!-- Sequence "EventAction" of type - "Geant4EventActionSequence" --> - <action name="Geant4TestEventAction/UserEvent_1"> <!-- Anonymous action --> - <properties Property_int="01234" <!-- Properties go inline --> - Property_double="1e11" - Property_string="'Hello_1'"/> - </action> - <action name="UserEvent_2"/> <!-- Global action defined in "actions" --> - <!-- Only the name is referenced here --> - <action name="Geant4Output2ROOT/RootOutput"> <!-- ROOT I/O action --> - <properties Output="simple.root"/> <!-- Output file property --> - </action> - <action name="Geant4Output2LCIO/LCIOOutput"> <!-- LCIO output action --> - <properties Output="simple.lcio"/> <!-- Output file property --> - </action> - </sequence> - - - <sequence sd="SiTrackerBarrel" type="Geant4SensDetActionSequence"> - <filter name="GeantinoRejector"/> - <filter name="EnergyDepositMinimumCut"/> - <action name="Geant4SimpleTrackerAction/SiTrackerBarrelHandler"/> - </sequence> - <sequence sd="SiTrackerEndcap" type="Geant4SensDetActionSequence"> - <filter name="GeantinoRejector"/> - <filter name="EnergyDepositMinimumCut"/> - <action name="Geant4SimpleTrackerAction/SiTrackerEndcapHandler"/> - </sequence> - <!-- ... next sequence ... --> - </sequences> -</geant4_setup> -\end{code} -Here firstly the \bold{EventAction} sequence is defined with its members. -Secondly a sensitive detector sequence is defined for the subdetector -\tts{SiTrackerBarrel} of type \tts{Geant4SensDetActionSequence}. -The sequence uses two filters: \tts{GeantinoRejector} to not generate hits -from geantinos and \tts{EnergyDepositMinimumCut} to enforce a minimal energy deposit. -These filters are global i.e. they may be applied by many subdetectors. -The setup of global filters is described in -Section~\ref{sec:ddg4-setup-xml-geant4-filters}. -Finally the action \tts{SiTrackerEndcapHandler} of type \tts{Geant4SimpleTrackerAction} -is chained, which collects the deposited energy and -creates a collection of hits. The \tts{Geant4SimpleTrackerAction} is a template -callback to illustrate the usage of sensitive elements in \DDG. -The resulting hit collection of these handlers by default have the same name as the -object instance name. -Analogous below the sensitive detector sequence for the subdetector -\tts{SiTrackerEndcap} is shown, which reuses the same filter actions, but will build its own -hit collection. - -\noindent -\bold{Please note:} -\begin{itemize}\itemcompact -\item \bold{It was already mentioned, but once again}: Event-, run-, generator-, tracking-, - stepping- and stacking actions sequences have predefined names! - These names are fixed and part of the \bold{common knowledge}, they cannot be altered. - Please refer to - Section~\ref{sec:ddg4-user-manual-implementation-geant4action-sequences} - for the names of the global action sequences. -\item the sensitive detector sequences are matched by the attribute \tts{sd} to the - subdetectors created with the \DDhep detector description package. Values must match! -\item In the event that several xml files are parsed it is absolutely vital that - the \tts{<actions>} section is interpreted \bold{before} the \tts{sequences}. -\item For each XML file several \tts{<sequences>} are allowed. -\noindent -\end{itemize} - -%============================================================================= -\subsubsection{Setup of Geant4 Sensitive Detectors} -\label{sec:ddg4-setup-xml-geant4-sensitive detectors} -%============================================================================= -\begin{code} - <geant4_setup> - <sensitive_detectors> - <sd name="SiTrackerBarrel" - type="Geant4SensDet" - ecut="10.0*MeV" - verbose="true" - hit_aggregation="position"> - </sd> - <!-- ... next sensitive detector ... --> - </sensitive_detectors> - </geant4_setup> -\end{code} - - - -%============================================================================= -\subsubsection{Miscellaneous Setup of Geant4 Objects} -\label{sec:ddg4-setup-xml-geant4-objects} -%============================================================================= - -\noindent -This section is used for the flexible setup of auxiliary objects such as the -electromagnetic fields used in Geant4: -\begin{code} - <geant4_setup> - <properties> - <attributes name="geant4_field" - id="0" - type="Geant4FieldSetup" - object="GlobalSolenoid" - global="true" - min_chord_step="0.01*mm" - delta_chord="0.25*mm" - delta_intersection="1e-05*mm" - delta_one_step="0.001*mm" - eps_min="5e-05*mm" - eps_max="0.001*mm" - stepper="HelixSimpleRunge" - equation="Mag_UsualEqRhs"> - </attributes> - ... - </properties> - </geant4_setup> -\end{code} -Important are the tags \tts{type} and \tts{object}, which are used to firstly -define the plugin to be called and secondly define the object from the \DDhep -description to be configured for the use within Geant4. - -%============================================================================= -\subsubsection{Setup of Geant4 Phases} -\label{sec:ddg4-setup-xml-geant4-phases} -%============================================================================= - -\noindent -Phases are configured as shown below. -However, the use is \bold{discouraged}, -since it is not yet clear if there are appropriate use cases! -\begin{code} - <phases> - <phase type="RunAction/begin"> - <action name="RunInit"/> - <action name="Geant4TestRunAction/UserRunInit"> - <properties Property_int="1234" - Property_double="5e15" - Property_string="'Hello_2'"/> - </action> - </phase> - <phase type="EventAction/begin"> - <action name="UserEvent_2"/> - </phase> - <phase type="EventAction/end"> - <action name="UserEvent_2"/> - </phase> - ... - </phases> -\end{code} - -\newpage -%============================================================================= -\subsection{Setting up DDG4 using ROOT-CINT} -\label{sec:ddg4-implementation-setup-root-cint} -%============================================================================= - -\noindent -The setup of \DDG directly from the the ROOT interpreter using the AClick -mechanism is very simple, but mainly meant for purists (like me ;-)), -since it is nearly equivalent to the explicit setup within a \tts{C++} -main program. -The following code section shows how to do it. For explanation the code -segment is discussed below line by line. -\begin{code} -#include "DDG4/Geant4Config.h" -#include "DDG4/Geant4TestActions.h" -#include "DDG4/Geant4TrackHandler.h" -#include <iostream> - -using namespace std; -using namespace DD4hep; -using namespace DD4hep::Simulation; -using namespace DD4hep::Simulation::Test; -using namespace DD4hep::Simulation::Setup; - -#if defined(__MAKECINT__) -#pragma link C++ class Geant4RunActionSequence; -#pragma link C++ class Geant4EventActionSequence; -#pragma link C++ class Geant4SteppingActionSequence; -#pragma link C++ class Geant4StackingActionSequence; -#pragma link C++ class Geant4GeneratorActionSequence; -#pragma link C++ class Geant4Action; -#pragma link C++ class Geant4Kernel; -#endif - -SensitiveSeq::handled_type* setupDetector(Kernel& kernel, const std::string& name) { - SensitiveSeq sd = SensitiveSeq(kernel,name); - Sensitive sens = Sensitive(kernel,"Geant4TestSensitive/"+name+"Handler",name); - sd->adopt(sens); - sens = Sensitive(kernel,"Geant4TestSensitive/"+name+"Monitor",name); - sd->adopt(sens); - return sd; -} - -void exampleAClick() { - Geant4Kernel& kernel = Geant4Kernel::instance(LCDD::getInstance()); - kernel.loadGeometry("file:../DD4hep.trunk/DDExamples/CLICSiD/compact/compact.xml"); - kernel.loadXML("DDG4_field.xml"); - - GenAction gun(kernel,"Geant4ParticleGun/Gun"); - gun["energy"] = 0.5*GeV; // Set properties - gun["particle"] = "e-"; - gun["multiplicity"] = 1; - kernel.generatorAction().adopt(gun); - - Action run_init(kernel,"Geant4TestRunAction/RunInit"); - run_init["Property_int"] = 12345; - kernel.runAction().callAtBegin (run_init.get(),&Geant4TestRunAction::begin); - kernel.eventAction().callAtBegin(run_init.get(),&Geant4TestRunAction::beginEvent); - kernel.eventAction().callAtEnd (run_init.get(),&Geant4TestRunAction::endEvent); - - Action evt_1(kernel,"Geant4TestEventAction/UserEvent_1"); - evt_1["Property_int"] = 12345; // Set properties - evt_1["Property_string"] = "Events"; - kernel.eventAction().adopt(evt_1); - - EventAction evt_2(kernel,"Geant4TestEventAction/UserEvent_2"); - kernel.eventAction().adopt(evt_2); - - kernel.runAction().callAtBegin(evt_2.get(),&Geant4TestEventAction::begin); - kernel.runAction().callAtEnd (evt_2.get(),&Geant4TestEventAction::end); - - setupDetector(kernel,"SiVertexBarrel"); - setupDetector(kernel,"SiVertexEndcap"); - // .... more subdetectors here ..... - setupDetector(kernel,"LumiCal"); - setupDetector(kernel,"BeamCal"); - - kernel.configure(); - kernel.initialize(); - kernel.run(); - std::cout << "Successfully executed application .... " << std::endl; - kernel.terminate(); -} -\end{code} - -\noindent -\begin{tabular} {l||p{0cm}} -\docline{Line}{} -\docline{1}{The header file \tts{Geant4Config.h} contains a set of wrapper - classes to easy the creation of objects using the plugin mechanism and setting - properties to \tts{Geant4Action} objects. These helpers and the corresponding - functionality are not included in the wrapped classes themselves to not - clutter the code with stuff only used for the setup. - All contained objects are in the namespace \tts{DD4hep::Simulation::Setup}}. -\docline{6-10}{Save yourself specifying all the namespaces objects are in....} -\docline{13-19}{CINT processing pragmas. - Classes defined here will be available at the ROOT prompt - after this AClick is loaded.} -\docline{22-29}{Sampler to fill the sensitive detector sequences for each - subdetector with two entries: a handler and a monitor action. - Please note, that this here is example code and in real life specialized actions - will have to be provided for each subdetector.} -\docline{31}{Let's go for it. here the entry point starts....} -\docline{32}{Create the \tts{Geant4Kernel} object.} -\docline{33}{Load the geometry into \DDhep.} -\docline{34}{Redefine the setup of the sensitive detectors.} -\docline{36-40}{Create the generator action of type \tts{Geant4ParticleGun} with name - \tts{Gun}, set non-default properties and activate the configured object - by attaching it to the \tts{Geant4Kernel}.} -\docline{42-46}{Create a user defined begin-of-run action callback, set the properties - and attach it to the begin of run calls. To collect statistics extra member functions - are registered to be called at the beginning and the end of each event.} -\docline{48-51}{Create a user defined event action routine, set its properties - and attach it to the event action sequence.} -\docline{53-54}{Create a second event action and register it to the event action sequence. - This action will be called after the previously created action.} -\docline{56-57}{For this event action we want to receive callbacks at start- - and end-of-run to produce additional summary output.} -\docline{59-63}{Call the sampler routine to attach test actions to the subdetectors defined.} -\docline{65-66}{Configure, initialize and run the Geant4 application. - Most of the Geant4 actions will only be created here and the action sequences - created before will be attached now.} -\docline{69}{Terminate the Geant4 application and exit.} -\end{tabular} - -\newpage -\noindent -CINT currently cannot handle pointers to member functions~\footnote{This may change -in the future once ROOT uses \tts{clang} and \tts{cling} as the interpreting engine.}. -Hence the above AClick only works in compiled mode. To invoke the compilation the following -action is necessary from the ROOT prompt: - - -\begin{code} -$> root.exe - ******************************************* - * * - * W E L C O M E to R O O T * - * * - * Version 5.34/10 29 August 2013 * - * * - * You are welcome to visit our Web site * - * http://root.cern.ch * - * * - ******************************************* - -ROOT 5.34/10 (heads/v5-34-00-patches@v5-34-10-5-g0e8bac8, Sep 04 2013, 11:52:19 on linux) - -CINT/ROOT C/C++ Interpreter version 5.18.00, July 2, 2010 -Type ? for help. Commands must be C++ statements. -Enclose multiple statements between { }. -root [0] .X initAClick.C -.... Setting up the CINT include pathes and the link statements. - -root [1] .L ../DD4hep.trunk/DDG4/examples/exampleAClick.C+ -Info in <TUnixSystem::ACLiC>: creating shared library ....exampleAClick_C.so -.... some Cint warnings concerning member function pointers ..... - -root [2] exampleAClick() -.... and it starts ... -\end{code} - -\noindent -The above scripts are present in the DDG4/example directory located in svn. -The initialization script \tts{initAClick.C} may require customization -to cope with the installation paths. - -%============================================================================= -\subsection{Setting up DDG4 using Python} -\label{sec:ddg4-implementation-setup-python} -%============================================================================= - -\noindent -Given the reflection interface of ROOT, the setup of the simulation interface -using DD4hep is of course also possible using the python interpreted language. -In the following code example the setup of Geant4 using the \tw{ClicSid} -example is shown using python~\footnote{For comparison, the same example was -used to illustrate the setup using XML files.}. - -\begin{code} -import DDG4 -from SystemOfUnits import * - -""" - - DD4hep example setup using the python configuration - - @author M.Frank - @version 1.0 - -""" -def run(): - kernel = DDG4.Kernel() - kernel.loadGeometry("file:../DD4hep.trunk/DDExamples/CLICSiD/compact/compact.xml") - kernel.loadXML("DDG4_field.xml") - - lcdd = kernel.lcdd() - print '+++ List of sensitive detectors:' - for i in lcdd.detectors(): - o = DDG4.DetElement(i.second) - sd = lcdd.sensitiveDetector(o.name()) - if sd.isValid(): - print '+++ %-32s type:%s'%(o.name(), sd.type(), ) - - # Configure Run actions - run1 = DDG4.RunAction(kernel,'Geant4TestRunAction/RunInit') - run1.Property_int = 12345 - run1.Property_double = -5e15*keV - run1.Property_string = 'Startrun: Hello_2' - print run1.Property_string, run1.Property_double, run1.Property_int - run1.enableUI() - kernel.registerGlobalAction(run1) - kernel.runAction().add(run1) - - # Configure Event actions - evt2 = DDG4.EventAction(kernel,'Geant4TestEventAction/UserEvent_2') - evt2.Property_int = 123454321 - evt2.Property_double = 5e15*GeV - evt2.Property_string = 'Hello_2 from the python setup' - evt2.enableUI() - kernel.registerGlobalAction(evt2) - - evt1 = DDG4.EventAction(kernel,'Geant4TestEventAction/UserEvent_1') - evt1.Property_int=01234 - evt1.Property_double=1e11 - evt1.Property_string='Hello_1' - evt1.enableUI() - - kernel.eventAction().add(evt1) - kernel.eventAction().add(evt2) - - # Configure I/O - evt_root = DDG4.EventAction(kernel,'Geant4Output2ROOT/RootOutput') - evt_root.Control = True - evt_root.Output = "simple.root" - evt_root.enableUI() - - evt_lcio = DDG4.EventAction(kernel,'Geant4Output2LCIO/LcioOutput') - evt_lcio.Output = "simple_lcio" - evt_lcio.enableUI() - - kernel.eventAction().add(evt_root) - kernel.eventAction().add(evt_lcio) - - # Setup particle gun - gun = DDG4.GeneratorAction(kernel,"Geant4ParticleGun/Gun") - gun.energy = 0.5*GeV - gun.particle = 'e-' - gun.multiplicity = 1 - gun.enableUI() - kernel.generatorAction().add(gun) - - # Setup global filters for use in sensitive detectors - f1 = DDG4.Filter(kernel,'GeantinoRejectFilter/GeantinoRejector') - f2 = DDG4.Filter(kernel,'ParticleRejectFilter/OpticalPhotonRejector') - f2.particle = 'opticalphoton' - f3 = DDG4.Filter(kernel,'ParticleSelectFilter/OpticalPhotonSelector') - f3.particle = 'opticalphoton' - f4 = DDG4.Filter(kernel,'EnergyDepositMinimumCut') - f4.Cut = 10*MeV - f4.enableUI() - kernel.registerGlobalFilter(f1) - kernel.registerGlobalFilter(f2) - kernel.registerGlobalFilter(f3) - kernel.registerGlobalFilter(f4) - - # First the tracking detectors - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/SiVertexBarrel') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleTrackerAction/SiVertexBarrelHandler','SiVertexBarrel') - seq.add(act) - seq.add(f1) - seq.add(f4) - act.add(f1) - - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/SiVertexEndcap') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleTrackerAction/SiVertexEndcapHandler','SiVertexEndcap') - seq.add(act) - seq.add(f1) - seq.add(f4) - - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/SiTrackerBarrel') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleTrackerAction/SiTrackerBarrelHandler','SiTrackerBarrel') - seq.add(act) - seq.add(f1) - seq.add(f4) - - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/SiTrackerEndcap') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleTrackerAction/SiTrackerEndcapHandler','SiTrackerEndcap') - seq.add(act) - - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/SiTrackerForward') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleTrackerAction/SiTrackerForwardHandler','SiTrackerForward') - seq.add(act) - - # Now the calorimeters - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/EcalBarrel') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/EcalBarrelHandler','EcalBarrel') - seq.add(act) - - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/EcalEndcap') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/EcalEndCapHandler','EcalEndcap') - seq.add(act) - - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/HcalBarrel') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/HcalBarrelHandler','HcalBarrel') - act.adoptFilter(kernel.globalFilter('OpticalPhotonRejector')) - seq.add(act) - - act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/HcalOpticalBarrelHandler','HcalBarrel') - act.adoptFilter(kernel.globalFilter('OpticalPhotonSelector')) - seq.add(act) - - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/HcalEndcap') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/HcalEndcapHandler','HcalEndcap') - seq.add(act) - - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/HcalPlug') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/HcalPlugHandler','HcalPlug') - seq.add(act) - - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/MuonBarrel') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/MuonBarrelHandler','MuonBarrel') - seq.add(act) - - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/MuonEndcap') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/MuonEndcapHandler','MuonEndcap') - seq.add(act) - - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/LumiCal') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/LumiCalHandler','LumiCal') - seq.add(act) - - seq = DDG4.SensitiveSequence(kernel,'Geant4SensDetActionSequence/BeamCal') - act = DDG4.SensitiveAction(kernel,'Geant4SimpleCalorimeterAction/BeamCalHandler','BeamCal') - seq.add(act) - - # Now build the physics list: - phys = kernel.physicsList() - phys.extends = 'FTFP_BERT' - #phys.transportation = True - phys.decays = True - phys.enableUI() - - ph = DDG4.PhysicsList(kernel,'Geant4PhysicsList/Myphysics') - ph.addParticleConstructor('G4BosonConstructor') - ph.addParticleConstructor('G4LeptonConstructor') - ph.addParticleProcess('e[+-]','G4eMultipleScattering',-1,1,1) - ph.addPhysicsConstructor('G4OpticalPhysics') - ph.enableUI() - phys.add(ph) - - phys.dump() - - kernel.configure() - kernel.initialize() - kernel.run() - kernel.terminate() - -if __name__ == "__main__": - run() - -\end{code} - -\newpage -%============================================================================= -\subsection{A Simple Example} -\label{sec:ddg4-implementation-simple-example} -%============================================================================= -\noindent -Bla-bal. - -\newpage -%============================================================================= -\section{Higher Level Components} -\label{sec:ddg4-implementation-higher-level-components} -%============================================================================= -\noindent -Layered components, which base on the general framework implement higher -level functionality such as the handling of Monte-Carlo truth associations -between simulated energy deposits and the corresponding particles or the -generic handling of input to the simulation. - -\noindent -To generalize such common behavior it is mandatory that the participating -components collaborate and understand the data components the commonly access. -The data model is shown in Figure~\ref{fig:ddg4-event-data-model}. -\begin{figure}[t] - \begin{center} - \includegraphics[width=120mm] {DDG4_event_data_model.png} - \caption{The DDG4 event data model.} - \label{fig:ddg4-event-data-model} - \end{center} -\end{figure} - -\noindent -Please note, that this data model is by no means to be made persistent -and used for physics user analysis. This model is optimized to support -the simulation process and the necessary user actions to handle MC truth, -to easily and relatively fast look up and modify parent-daughter -relationships etc. This choice is based on the assumption, that the -additional overhead to convert particles at the input/output -stage is small compared to the actual resource consumption of Geant4 -to simulate the proper detector response. -On the other hand this choice has numerous advantages: -\begin{itemize}\itemcompact -\item Accepting the fact to convert input records allows to adapt - DDG4 in a simple and flexible manner to any input format. Currently - supported is the input from raw {\tw{LCIO}} files, {\tw{StdHep}} - records using {\tw{LCIO}} and {\tw{ASCII}} files using the - {\tw{HEPEvt}} format. -\item Similarly as for the input stage, also the output format - can be freely chosen by the clients. -\item No assumptions was made concerning the structure to store - information from energy deposits. Any information extract produced - by the sensitive actions can be adapted provided at the output - stage the proper conversion mechanism is present. The sensitive - detectors provided by DDG4 are {\bf{optional only and by no means mandatory}}. - User defined classes may be provided at any time. Appropriate tools - to extract MC truth information is provided at the output stage. -\item The modular approach of the action sequences described - in~\ref{sec:ddg4-user-manual-implementation-geant4action-sequences} - allows to easily extend the generation sequence to handle multiple - simultaneous interactions, event overlay or spillover response - very easily~\footnote{The handling of spillover is only possible - if during the digitization step the correct signal shape corresponding - to the shift of signal creation is taken into account.} -\end{itemize} - -\noindent -In section~\ref{sec:ddg4-implementation-input-handling} the generic mechanism -of input data handling is described. \\ -In section~\ref{sec:ddg4-implementation-particle-handling} the MC truth -handling is discussed. \\ -In section~\ref{sec:ddg4-implementation-output-handling} we describe the -output mechanism. -\newpage - -%============================================================================= -\subsection{Input Data Handling} -\label{sec:ddg4-implementation-input-handling} -%============================================================================= -\begin{figure}[t] - \begin{center} - \includegraphics[width=160mm] {DDG4_input_stage.png} - \caption{The generic handling of input sources to DDG4.} - \label{fig:ddg4-input-stage} - \end{center} -\end{figure} - -\noindent -Input handling has several stages and uses several modules: -\begin{itemize}\itemcompact -\item First the data structures \tw{Geant4PrimaryEvent}, - \tw{Geant4PrimaryInteraction} and \tw{Geant4\-Primary}\-\tw{Map} are initialized - by the action \tw{Geant4GenerationActionInit} - and attached to the {\tw{Geant4Event}} structure. -\item The initialization is then followed by any number of input modules. - Typically each input module add one interaction. Each interaction has a - unique identifier, which is propagated later to all particles. Hence all - primary particles can later be unambiguously be correlated to one of the - initial interactions. - Each instance of a \tw{Geant4InputAction} creates and fills a separate instance - of a \tw{Geant4PrimaryInteraction}. - In section~\ref{sec:ddg4-implementation-geant4inputaction} the functionality and - extensions are discussed in more detail. -\item All individual primary interactions are then merged to only single record - using the \tw{Geant4}\-\tw{Interaction}\-\tw{Merger} component. - This components fills the \tw{Geant4PrimaryInteraction} registered to the - \tw{Geant4Event}, which serves as input record for the next component, -\item the \tw{Geant4PrimaryHandler}. The primary handler creates the proper - \tw{G4PrimaryParticle} and \tw{G4PrimaryVertex} objects passed to \tw{Geant4}. - After this step all event related user interaction with Geant4 has completed, - and the detector simulation may commence. -\end{itemize} -All modules used are subclasses of the {\tw{Geant4}\-\tw{Generator}\-\tw{Action}} and must be -added to the \tw{Geant4}\-\tw{Generator}\-\tw{Action}\-\tw{Sequence} as described -in~\ref{sec:ddg4-user-manual-implementation-geant4action-sequences}. -\newpage - -%============================================================================= -\subsection{Anatomy of the Input Action} -\label{sec:ddg4-implementation-geant4inputaction} -%============================================================================= - -\newpage -One input action fills one primary interaction. -\tw{Geant4InputAction} instances may be followed by decorators, which -allow to to smear primary vertex (\tw{Geant4InteractionVertexSmear}) or -to boost the primary vertex \tw{Geant4InteractionVertexBoost} and all -related particles/vertices. - - -Please note, that a possible reduction of particles in -the output record may break this unambiguous relationship between -"hits" and particles. -...... - -%============================================================================= -\subsection{Monte-Carlo Truth Handling} -\label{sec:ddg4-implementation-particle-handling} -%============================================================================= - -\newpage -...... - -%============================================================================= -\section{Output Data Handling} -\label{sec:ddg4-implementation-output-handling} -%============================================================================= - -\newpage -...... - -%============================================================================= -\section{Existing DDG4 components} -%============================================================================= -\noindent -In the introduction the longterm goal was expressed, that with DDG4 users -should be able to pick components from a growing palette and connect the -selected components using the setup mechanisms described in -Section~\ref{sec:ddg4-implementation-setup}. - -\noindent -Such a palette based approach obviously depends on the availability of -documentation for existing components describing the properties -of each component and the interaction of each component within the \DDG -framework. - -\noindent -All components defer from the basic type \tts{Geant4Action}. This means -\bold{all} components have the \bold{default} properties described in the -table below: - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l l p{9cm} } -\hline -Component Properties: & & \tts{default} \\ -\hline -\bold{OuputLevel} & [int] & Output level of the component to customize printouts \\ -\bold{Name} & [string] & Component name [read-only] \\ -\bold{Control} & [boolean] & Steering of the Geant4 Messenger creation \\ -\hline -\end{tabular} - - -\vspace{5cm} - -\begin{center} -{\large{\bf{ -\begin{tabular} {| p{15cm} |} -\hline\space \\ - -\noindent -{\underline{Important notice for developers:}} \\ - -\noindent -Since the documentation of developed components is VERY important, -please never forget to supply the corresponding documentation.\\ -\\ -\noindent -At least supply the minimal documentation ash shown below -in the appended examples for the "Simple" detector response and I/O -components. -\\ \space\hline -\end{tabular} -}}} -\end{center} -\clearpage - -%============================================================================= -\subsection{Generic Action Modules} -%============================================================================= -\noindent -%============================================================================= -\subsubsection{Geant4UIManager} -%============================================================================= -\noindent -The {\tt{Geant4UIManager}} handles interactivity aspects between Geant4, -its command handlers (i.e. terminal) and the various components the actions -interact. - -\noindent -The {\tt{Geant4UIManager}} is a component attached to the {\tt{Geant4Kernel}} -object. All properties of all {\tt{Geant4Action}} instances may be exported to -\tw{Geant4} messengers and {\em{may}} hence be accessible directly from -the \tw{Geant4} prompt. To export properties from any action, call the -{\tt{enableUI()}} method of the action. -\noindent -The callback signature is: \tw{void operator()(G4Event* event)}. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4} \\ -\bold{File name} & \tts{DDG4/src/Geant4.cpp} \\ -\bold{Type} & \tts{Geant4Action} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\hline -\bold{SessionType} (string) & Session type (csh, tcsh, etc. \\ -\bold{SetupUI} (string) & Name of the UI macro file \\ -\bold{SetupVIS} (string) & Name of the visualization macro file \\ -\bold{HaveVIS} (bool) & Flag to instantiate Vis manager - (def:false, unless VisSetup set) \\ -\bold{HaveUI} (bool) & Flag to instantiate UI (default=true) \\ -\end{tabular} - -%============================================================================= -\subsubsection{Geant4Random} -%============================================================================= -\noindent -Mini interface to the random generator of the application. -Necessary, that on every object creates its own instance, but accesses -the main instance available through the \tw{Geant4Context}. - -\noindent -This is mandatory to ensure reproducibility of the event generation -process. Particular objects may use a dependent generator from -an experiment framework like \tw{GAUDI}. - -\noindent -internally the engine factory mechanism of \tw{CLHEP} is used. Please refer -there within for valid engine names and the random seeding mechanism, -which may vary between different engines. - -\noindent -Any number of independent random objects may be created and used -in parallel. This however, is not advised to ensure reproducibility. - -\noindent -The first instance of the random action is automatically set -to be the \tw{Geant4} instance. If another instance should be used by -\tw{Geant4}, use \tw{setMainInstance(Geant4Random* ptr)} class method to -override this behavior. -Provision, steered by options, is taken to ensure the \tw{gRandom} -of \tw{ROOT} uses the same random number engine. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4} \\ -\bold{File name} & \tts{DDG4/src/Geant4Random.cpp} \\ -\bold{Type} & \tts{Geant4Random} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\hline -\bold{File} (string) & File name if initialized from file. \\ - & If set, engine name and seeds are ignored \\ -\bold{Engine} (string) & Engine type name. \\ - & All engines defined in the - \tw{CLHEP::EngineFactory} class are available. - If no type is supplied the engine from the - HepRandom generator instance is taken. \\ -\bold{Seed} (long) & Initial random seed. \\ - & Default: 123456789. \\ - & If not ZERO terminated, termination is added.\\ -\bold{Replace\_gRandom} (bool)& Flag to replace the \tw{ROOT} \tw{gRandom} - instance with this random number engine. - This ensures \tw{ROOT} and \tw{Geant4} use the same - random number engine, hence the same random sequence. - \\ -\end{tabular} - - -%============================================================================= -\subsection{Predefined Geant4 Physics List Objects} -%============================================================================= -\noindent -The physics list may be defined entirely data driven using the factory mechanism -using a variety of predefined objects. Though users are free to define private -physics lists, typically the predefined physics lists from \tw{Geant4} are used. - -\noindent -The inventory changes over time, new lists appear and obsolete lists are purged, -hence we will not list them explicitly here. -For the inventory of available physics lists, please refer to the implementation files: - -\noindent -\begin{itemize}\itemcompact -\item Inventory of predefined physics lists, which may be inherited:\\ -\detdesc{html/_geant4_physics_lists_8cpp_source.html} -{DDG4/plugins/Geant4PhysiscsLists.cpp} -\item Inventory of predefined physics constructors, which may be instantiated:\\ -\detdesc{html/_geant4_physics_constructors_8cpp_source.html} -{DDG4/plugins/Geant4PhysicsConstructors.cpp} -\item Inventory of predefined process constructors, which may be instantiated:\\ -\detdesc{html/_geant4_processes_8cpp_source.html} -{DDG4/plugins/Geant4Processes.cpp} -\item Inventory of predefined particle constructors, which may be instantiated:\\ -\detdesc{html/_geant4_particles_8cpp_source.html} -{DDG4/plugins/Geant4Particles.cpp} -\end{itemize} -\newpage - -%============================================================================= -\subsection{Geant4 Generation Action Modules} -%============================================================================= -\noindent -Here we discuss modules, which are intrinsically part of DDG4 and may be -attached to the {\tt{Geant4GeneratorActionSequence}}. - -%============================================================================= -\subsubsection{Base class: Geant4GeneratorAction} -%============================================================================= -\noindent -The \tw{Geant4GeneratorAction} is called for every event. -During the callback all particles are created which form the -microscopic kinematic action of the particle collision. -This input may either origin directly from an event generator program -or come from file. - -\noindent -The callback signature is: void operator()(G4Event* event) -\noindent -See also: -\detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_generator_action.html} -{\tts{Geant4EventAction}} in the doxygen documentation. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4GeneratorAction} \\ -\bold{File name} & \tts{DDG4/src/Geant4GeneratorAction.cpp} \\ -\bold{Type} & \tts{Geant4Action, Geant4GeneratorAction} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\hline -\end{tabular} - -%============================================================================= -\subsubsection{Geant4GeneratorActionSequence} -%============================================================================= -\noindent -The sequence dispatches the callbacks at the beginning -of an event to all registered \tw{Geant4GeneratorAction} members and all -registered callbacks. - -\noindent -See also: -\noindent -The {\tt{Geant4GeneratorActionSequence}} is directly steered by the single -instance of the {\tt{G4VUserPrimaryGeneratorAction}}, the Geant4 provided user hook, -which is private.\\ -See also: -\detdesc{html/struct_d_d4hep_1_1_simulation_1_1_geant4_user_generator_action.html} -{\tts{Geant4UserGeneratorAction}} and -\detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_generator_action_sequence.html} -{\tts{Geant4GeneratorActionSequence}} in the doxygen documentation. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4Geant4GeneratorActionSequence} \\ -\bold{File name} & \tts{DDG4/src/Geant4GeneratorAction.cpp} \\ -\bold{Type} & \tts{Geant4Action} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\hline -\end{tabular} - -%============================================================================= -\subsubsection{Geant4GeneratorActionInit} -%============================================================================= -\noindent -Initialize the Geant4Event objects to host generator and MC truth related information -Geant4 actions to collect the MC particle information. -This action should register all event extension required for the further -processing. We want to avoid that every client has to check if a given -object is present or not and than later install the required data structures. - -\noindent -These by default are extensions of type: -\begin{itemize}\itemcompact -\item \tw{Geant4PrimaryEvent} with multiple interaction sections, one for each interaction - This is the MAIN and ONLY information to feed Geant4 -\item \tw{Geant4PrimaryInteraction} containing the track/vertex information to create - the primary particles for Geant4. This record is build from the \tw{Geant4PrimaryEvent} - information. -\item \tw{Geant4PrimaryMap} a map of the \tw{Geant4Particles} converted to - \tw{G4PrimaryParticles} to ease particle handling later. -\item \tw{Geant4ParticleMap} the map of particles created during the event simulation. - This map has directly the correct particle offsets, so that the merging of - \tw{Geant4PrimaryInteraction} particles and the simulation particles is easy.... -\end{itemize} - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4Geant4GeneratorActionInit} \\ -\bold{File name} & \tts{DDG4/src/Geant4GeneratorActionInit.cpp} \\ -\bold{Type} & \tts{Geant4GeneratorAction} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\bold{Angle} (double) & \tts{Lorentz-Angle of boost} \\ -\bold{Mask} (int.bitmask) & \tts{Interaction identifier} \\ -\hline -\end{tabular} - -%============================================================================= -\subsubsection{Geant4InteractionVertexBoost} -%============================================================================= -\noindent -Boost the primary vertex and all particles outgoing the primary interaction in X-direction. - -\noindent -The interaction to be processed by the component is uniquely identified -by the {\bf{Mask}} property. Two primary interaction may not have the same -mask. - -\noindent -{\bold{Note [special use case]:}}\\ -If all contributing interactions of the one event \bold{registered -in the primary event at the time the action is called} should be handled by -one single component instance, set the {\bf{Mask}} property to {\bold{-1}}. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4InteractionVertexBoost} \\ -\bold{File name} & \tts{DDG4/src/Geant4InteractionVertexBoost.cpp} \\ -\bold{Type} & \tts{Geant4GeneratorAction} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\bold{Angle} (double) & \tts{Lorentz-Angle of boost} \\ -\bold{Mask} (int.bitmask) & \tts{Interaction identifier} \\ -\hline -\end{tabular} - -%============================================================================= -\subsubsection{Geant4InteractionVertexSmear} -%============================================================================= -\noindent -Smear the primary vertex and all particles outgoing the primary interaction. - -\noindent -The interaction to be processed by the component is uniquely identified -by the {\bf{Mask}} property. Two primary interaction may not have the same -mask. - -\noindent -{\bold{Note [special use case]:}}\\ -If all contributing interactions of the one event \bold{registered -in the primary event at the time the action is called} should be handled by -one single component instance, set the {\bf{Mask}} property to {\bold{-1}}. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4InteractionVertexSmear} \\ -\bold{File name} & \tts{DDG4/src/Geant4InteractionVertexSmear.cpp} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\bold{Offset} (PxPyPzEVector) & \tts{Smearing offset} \\ -\bold{Sigma} (PxPyPzEVector) & \tts{Sigma (Errors) on offset} \\ -\bold{Mask} (int.bitmask) & \tts{Interaction identifier} \\ -\hline -\end{tabular} - -%============================================================================= -\subsubsection{Geant4InteractionMerger} -%============================================================================= -\noindent -Merge all interactions created by each {\tt{Geant4InputAction}} into one single -record. The input records are taken from the item {\tt{Geant4PrimaryEvent}} -and are merged into the {\tt{Geant4PrimaryInteraction}} object attached to the -{\tt{Geant4Event}} event context. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4InteractionMerger} \\ -\bold{File name} & \tts{DDG4/src/Geant4InteractionMerger.cpp} \\ -\bold{Type} & \tts{Geant4GeneratorAction} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\hline -\end{tabular} - -%============================================================================= -\subsubsection{Geant4PrimaryHandler} -%============================================================================= -\noindent -Convert the primary interaction (object {\tt{Geant4PrimaryInteraction}} object -attached to the {\tt{Geant4Event}} event context) and pass the result -to Geant4 for simulation. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4PrimaryHandler} \\ -\bold{File name} & \tts{DDG4/src/Geant4PrimaryHandler.cpp} \\ -\bold{Type} & \tts{Geant4GeneratorAction} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\hline -\end{tabular} - -%============================================================================= -\subsubsection{Geant4ParticleGun} -%============================================================================= -\noindent -Implementation of a particle gun using Geant4Particles. - -\noindent -The {\tt{Geant4ParticleGun}} is a tool to shoot a number of -particles with identical properties into a given region of the -detector to be simulated. - -\noindent -The particle gun is a input source like any other and participates -in the general input stage merging process like any other input -e.g. from file. Hence, there may be several particle guns present -each generating it's own primary vertex. Use the mask property to -ensure each gun generates it's own, well identified primary vertex. - -\noindent -There is one 'user lazyness' support though: -If there is only one particle gun in use, the property 'Standalone', -which by default is set to true invokes the interaction merging and the -Geant4 primary generation directly. - -\noindent -The interaction to be created by the component is uniquely identified -by the {\bf{Mask}} property. Two primary interaction may not have the same -mask. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4PrimaryHandler} \\ -\bold{File name} & \tts{DDG4/src/Geant4PrimaryHandler.cpp} \\ -\bold{Type} & \tts{Geant4GeneratorAction} \\ -\hline -Component Properties: & default \\ -\bold{particle} (string) & Particle type to be shot \\ -\bold{energy} (double) & Particle energy in $MeV$ \\ -\bold{position} (XYZVector) & Pole position of the generated particles in $mm$\\ -\bold{direction} (XYZVector) & Momentum direction of the generated particles\\ -\bold{isotrop} (bool) & Isotropic particle directions in space. \\ -\bold{Mask} (int.bitmask) & Interaction identifier \\ -\bold{Standalone} (bool) & Setup for standalone execution \\ - & including interaction merging etc. \\ -\hline -\end{tabular} - -%============================================================================= -\subsubsection{Geant4ParticleHandler} -%============================================================================= -\noindent -Extract the relevant particle information during the simulation step. - -\noindent -This procedure works as follows: -\begin{itemize}\itemcompact -\item At the beginning of the event generation the object registers itself as - Monte-Carlo truth handler to the event context. -\item At the begin of each track action a particle candidate is created and filled - with all properties known at this time. -\item At each stepping action a flag is set if the step produced secondaries. -\item Sensitive detectors call the MC truth handler if a hit was created. - This fact is remembered. -\item At the end of the tracking action a first decision is taken if the candidate is to be - kept for the final record. -\item At the end of the event action finally all particles are reduced to the - final record. This logic can be overridden by a user handler to be attached. -\end{itemize} -\noindent -Any of these actions may be intercepted by a {\tt{Geant4UserParticleHandler}} -attached to the particle handler. -See class {\tt{Geant4UserParticleHandler}} for details. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{9cm} } -\hline -\bold{Class name} & \tts{Geant4ParticleHandler} \\ -\bold{File name} & \tts{DDG4/src/Geant4ParticleHandler.cpp} \\ -\bold{Type} & \tts{Geant4GeneratorAction} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\bold{KeepAllParticles} (bool) & Flag to keep entire particle record without any reduction. - This may result in a huge output record. \\ -\bold{SaveProcesses} (vector(string)) & Array of Geant4 process names, - which products and parent should NOT be reduced.\\ -\bold{MinimalKineticEnergy} (double) & Minimal energy below which particles should be - ignored unless other criteria - (Process, created hits, etc) apply.\\ -\hline -\end{tabular} -\newpage - -%============================================================================= -\subsection{Geant4 Event Action Modules} -%============================================================================= -\noindent - -%============================================================================= -\subsubsection{Base class: Geant4EventAction} -%============================================================================= -\noindent -The EventAction is called for every event. - -\noindent -This class is the base class for all user actions, which have -to hook into the begin- and end-of-event actions. -Typical use cases are the collection/computation of event -related properties. - -\noindent -Examples of this functionality may include for example: -\begin{itemize}\itemcompact -\item Reset variables summing event related information in the - begin-event callback. -\item Monitoring activities such as filling histograms - from hits collected during the end-event action. -\end{itemize} -See also: -\detdesc{html/class_d_d4hep_1_1_simulation_1_1_geant4_event_action.html} -{\tts{Geant4EventAction}} in the doxygen documentation. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4EventAction} \\ -\bold{File name} & \tts{DDG4/src/Geant4EventAction.cpp} \\ -\bold{Type} & \tts{Geant4EventAction} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\hline -\end{tabular} - -%============================================================================= -\subsubsection{Geant4EventActionSequence} -%============================================================================= -\noindent - -\noindent -The {\tt{Geant4EventActionSequence}} is directly steered by the single -instance of the {\tt{G4UserEventAction}}, the Geant4 provided user hook, -which is private.\\ -See also: -\detdesc{html/struct_d_d4hep_1_1_simulation_1_1_geant4_user_event_action.html} -{\tts{Geant4UserEventAction}} in the doxygen documentation. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4EventAction} \\ -\bold{File name} & \tts{DDG4/src/Geant4EventAction.cpp} \\ -\bold{Type} & \tts{Geant4EventAction} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\hline -\end{tabular} - -%============================================================================= -\subsubsection{Geant4ParticlePrint} -%============================================================================= -\noindent -Geant4Action to print MC particle information. - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -\bold{Class name} & \tts{Geant4ParticlePrint} \\ -\bold{File name} & \tts{DDG4/src/Geant4ParticlePrint.cpp} \\ -\bold{Type} & \tts{Geant4EventAction} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\bold{OutputType} (bool) & Flag to steer output type. \\ - & 1: Print table of particles. \\ - & 2: Print table of particles. \\ - & 3: Print table and tree of particles. \\ -\bold{PrintHits} & Print associated hits to every particle (big output!)\\ -\hline -\end{tabular} -\newpage - - -%============================================================================= -\subsection{Sensitive Detectors} -%============================================================================= -\noindent - -%============================================================================= -\subsubsection{Geant4TrackerAction} -%============================================================================= -\noindent -Simple sensitive detector for tracking detectors. These trackers create one -single hit collection. The created hits may be written out with the output -modules described in Section~\ref{sec:ddg4-components-IO-ROOT-simple} -and~\ref{sec:ddg4-components-IO-LCIO-simple}. \\ -The basic specifications are: - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -Basics: & \\ -\hline -\bold{Class name} & \tts{Geant4SensitiveAction<Geant4Tracker>} \\ -\bold{File name} & \tts{DDG4/plugins/Geant4SDActions.cpp} \\ -\bold{Hit collection} & \tts{Name of the readout object} \\ -\bold{Hit class} & \tts{Geant4Tracker::Hit} \\ -\bold{File name} & \tts{DDG4/include/Geant4Data.h} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\hline -\end{tabular} - -%============================================================================= -\subsubsection{Geant4CalorimeterAction} -%============================================================================= -\noindent -Simple sensitive detector for calorimeters. The sensitive detector creates one -single hit collection. The created hits may be written out with the output -modules described in Section~\ref{sec:ddg4-components-IO-ROOT-simple} -and~\ref{sec:ddg4-components-IO-LCIO-simple}. \\ -The basic specifications are: - -\vspace{0.5cm} -\noindent -\begin{tabular}{ l p{10cm} } -\hline -Basics: & \\ -\hline -\bold{Class name} & \tts{Geant4SensitiveAction<Geant4Calorimeter>} \\ -\bold{File name} & \tts{DDG4/plugins/Geant4SDActions.cpp} \\ -\bold{Hit collection} & \tts{Name of the readout object} \\ -\bold{Hit class} & \tts{Geant4Calorimeter::Hit} \\ -\bold{File name} & \tts{DDG4/include/Geant4Data.h} \\ -\hline -\bold{Component Properties:} & defaults apply \\ -\hline -\end{tabular} - -\newpage - -%============================================================================= -\subsection{I/O Components} -%============================================================================= -\noindent - -%============================================================================= -\subsubsection{ROOT Output "Simple"} -\label{sec:ddg4-components-IO-ROOT-simple} -%============================================================================= -\noindent - -%============================================================================= -\subsubsection{LCIO Output "Simple"} -\label{sec:ddg4-components-IO-LCIO-simple} -%============================================================================= -\noindent - - +\input{DDG4Manual-Introduction.tex} +\input{DDG4Manual-Implementation.tex} +\input{DDG4Manual-Setup.tex} +\input{DDG4Manual-HighLevel.tex} +\input{DDG4Manual-MT.tex} +\input{DDG4Manual-Components.tex} %============================================================================= \newpage @@ -2415,6 +93,12 @@ Basics: & \\ \bibitem{bib:DDSegmentations} C.Grefe et al., "The DDSegmentation package", Non existing documentation to be written. +\bibitem{bib:Geant4-multi-threading} Geant4 Multi threading Guides. + Please see for details:\\ + https://twiki.cern.ch/twiki/bin/view/Geant4/Geant4MTAdvandedTopicsForApplicationDevelopers,\\ + https://twiki.cern.ch/twiki/bin/view/Geant4/QuickMigrationGuideForGeant4V10,\\ + http://geant4.slac.stanford.edu/tutorial/MC2015G4WS/Multithreading.pdf + \end{thebibliography} %============================================================================= \end{document} diff --git a/doc/doxygen/DD4hepGroups.h b/doc/doxygen/DD4hepGroups.h index 69e9a910d70e098204442f37b5f7062a38804b68..41f9bcce6f8f862dfee29d644883705d51273abb 100644 --- a/doc/doxygen/DD4hepGroups.h +++ b/doc/doxygen/DD4hepGroups.h @@ -81,4 +81,5 @@ namespace IO {} /// LCIO namespace. See http://lcio.desy.de \ingroup LCIO namespace UTIL {} + /**@}*/ diff --git a/doc/doxygen/ROOTClasses.h b/doc/doxygen/ROOTClasses.h index 717760732ffcee14cd281bb6e753d2c83178a643..7685ca802dae29076c4cce3c8e8609bb4650c9f6 100644 --- a/doc/doxygen/ROOTClasses.h +++ b/doc/doxygen/ROOTClasses.h @@ -1,21 +1,44 @@ -/// Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html +/// ROOT stuff +/** + * \defgroup ROOT Classes and namespaces from the ROOT project. See http://root.cern.ch + * @{ + */ + +/// Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html \ingroup ROOT +/** \see http://root.cern.ch/root/htmldoc/ClassIndex.html */ +class TEveElementList {}; + +/// Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html \ingroup ROOT +/** \see http://root.cern.ch/root/htmldoc/ClassIndex.html */ +class TGeoConeSeg {}; + +/// Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html \ingroup ROOT /** \see http://root.cern.ch/root/htmldoc/ClassIndex.html */ class TGeoConeSeg {}; -/// Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html +/// Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html \ingroup ROOT /** \see http://root.cern.ch/root/htmldoc/ClassIndex.html */ class TGeoExtension {}; -/// Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html +/// Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html \ingroup ROOT +/** \see http://root.cern.ch/root/htmldoc/ClassIndex.html */ +class TGLAnnotation {}; + +/// Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html \ingroup ROOT +/** \see http://root.cern.ch/root/htmldoc/ClassIndex.html */ +class TGMainFrame {}; + +/// Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html \ingroup ROOT /** \see http://root.cern.ch/root/htmldoc/ClassIndex.html */ class TNamed {}; -/// Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html +/// Class of the ROOT toolkit. See http://root.cern.ch/root/htmldoc/ClassIndex.html \ingroup ROOT /** \see http://root.cern.ch/root/htmldoc/ClassIndex.html */ class TObject {}; -/// ROOT utility namespace + +/// ROOT utility namespace. See http://root.cern.ch/root/htmldoc/ClassIndex.html namespace ROOT { /// ROOT namespace for mathematical operations and corresponding classes. namespace Math { diff --git a/doc/release.notes b/doc/release.notes index ea450104f752f49f8bf477c1d17bc4b489aa7883..f46c765f8a874415a6a8982152f970f895a24e00 100644 --- a/doc/release.notes +++ b/doc/release.notes @@ -3,6 +3,23 @@ DD4hep ---- Release Notes ================================= +2015-11-24 M.Frank + DDG4 + - Implementation of multi-threading mode. + To use and understand, please consult the DDG4 manual from the doc area. + - "Old" Single threaded mode and functionality is preserved. + - Numerous new classes supporting thread and master specific setup + functionality. + - Support for python configuration (see manual for details) + - Support for global Geant4Actions executing in thread reentrant shared mode. + (see manual for details) + - DDG4 examples: DDG4/examples/CLICSidSimu.py deleted and replaced with: + 1) DDG4/examples/SiDSim.py (single threaded, old example) + 2) DDG4/examples/SiDSim_MT.py (multi threaded version of SiDSim.py) + DDCore: + - Support user formats for the default printout statements for nicer printouts. + - Removal of compiler warnings + 2015-10-13 M.Frank DDG4 - Remove explicit constructors for modular physics lists.