Back to home page

EIC code displayed by LXR

 
 

    


Warning, /DD4hep/doc/usermanuals/DDG4/sections/MT.tex is written in an unsupported language. File is not indexed.

0001 
0002 %=============================================================================
0003 \section{Multi-Threading in \DDG}
0004 \label{sec:ddg4-multi-threading}
0005 %=============================================================================
0006 \subsection{Introductory Remarks}
0007 \label{sec:ddg4-multi-threading-introduction}
0008 %=============================================================================
0009 \noindent
0010 Multi-threading as supported by Geant4 is event driven. This means that 
0011 the simulation of a given event is handled by one single thread.
0012 Geant4 provides specific extensions to ease the users the use of its 
0013 multi-threaded extensions~\cite{bib:Geant4-multi-threading}~\footnote{Please
0014 note that the whole of Geant4 and your client code must be compiled with
0015 the compile flag ${\tts{-DGEANT4_BUILD_MULTITHREADED=ON}}$}.
0016 These extension divide in a formalized manner all actions to be performed
0017 to setup a Geant4 multi-threaded program into
0018 
0019 \begin{itemize}\itemcompact
0020 \item {\bf{common}} actions to be performed and shared by all threads.
0021 This includes the setup of the geometry and the physics list. The
0022 other main area are
0023 \item {\bf{thread-specific}} actions to be performed for each thread.
0024 These are composed by the user actions called during the processing of
0025 each run. These are the run-, event-, generation-, tracking-, 
0026 stepping and stacking actions.
0027 \end{itemize}
0028 
0029 \noindent
0030 To understand the interplay between \DDG and Geant4 let us quickly 
0031 recapitulate the Geant4 mechanism how to configure multiple threads.
0032 The setup of a multi-threaded application in Geant4 is centered around 
0033 two additional classes, which both deal with single- and multi-threaded 
0034 issues:
0035 
0036 \begin{itemize}\itemcompact
0037 \item {\tts{G4VUserActionInitialization}} class with 2 major callbacks:
0038         {\tts{Build()}} which is executed for each {\bf{worker thread}} and 
0039         {\tts{BuildForMaster()}} which is executed for master thread only.      
0040 \item {\tts{G4VUserDetectorConstruction}} class with the callbacks
0041     {\tts{Construct()}}, where the shared geometry is constructed and
0042     {\tts{ConstructSDandField()}} where the sensitive detectors and the
0043     electro magnetic fields are provided.
0044 \end{itemize}
0045 
0046 \noindent
0047 Both these Geant4 provided hooks are modeled in the standard \DDG 
0048 way as action queues, which allow a modular and fine grained setup
0049 as shown in Figure~\ref{fig:ddg4-user-initialization} and 
0050 Figure~\ref{fig:ddg4-detector-initialization}.
0051 \begin{figure}[t]
0052   \begin{center}
0053     \includegraphics[width=140mm] {DDG4-User-Initialization}
0054     \caption{The Geant4 user initialization sequence to setup DDG4
0055              in multi-threaded mode. The callbacks {\tts{buildMaster()}} 
0056              is only called in multi-threaded mode.}
0057     \label{fig:ddg4-user-initialization}
0058   \end{center}
0059 \end{figure}
0060 
0061 \noindent
0062 The \DDG framework ensures that all user callbacks are installed properly
0063 to the Geant4 run manager, which calls them appropriately at the correct time.
0064 
0065 \noindent
0066 \DDG provides three callbacks for each sequence. Each callback receives
0067 a temporary context argument, which may be used to shortcut access 
0068 to basic useful quantities:
0069 \begin{code}
0070     struct Geant4DetectorConstructionContext  {
0071       /// Reference to geometry object
0072       Geometry::LCDD&     lcdd;
0073       /// Reference to the world after construction
0074       G4VPhysicalVolume*  world;
0075       /// The cached geometry information
0076       Geant4GeometryInfo* geometry;
0077       /// G4 User detector initializer
0078       G4VUserDetectorConstruction* detector;
0079 };
0080 \end{code}
0081 
0082 \begin{figure}[h]
0083   \begin{center}
0084     \includegraphics[width=140mm] {DDG4-Detector-Construction}
0085     \caption{The Geant4 detector initialization sequence to setup DDG4.
0086         If supplied, Geant4 calls the components both, in the single-threaded 
0087         and in the multi-threaded mode.}
0088     \label{fig:ddg4-detector-initialization}
0089   \end{center}
0090 \end{figure}
0091 
0092 The callbacks and the expected functionality are:
0093 \begin{enumerate}
0094 \item First the detector geometry is constructed. This happens in the callback
0095     {\tts{constructGeo(...)}}. If a standard \DDhep geometry 
0096     is present, this is translation of the geometry could be done by simply 
0097     calling the plugin {\tts{Geant4DetectorGeometryConstruction}}. 
0098     Alternatively a user defined plugin could perform this action.
0099 \item Next the electromagnetic fields for the Geant4 particle tracking is
0100     constructed. A generic plugin {\tts{Geant4FieldTrackingConstruction}}
0101     may be attached. The corresponding setup parameters are listed in
0102     Section~\ref{sec:existing-ddg4-components}. 
0103     Alternatively a user defined plugin could perform this action.
0104 \item Finally the Geant4 sensitive detectors are instantiated and attached 
0105     to the sensitive volumes. For generic setups the plugin
0106     {\tts{Geant4DetectorSensitivesConstruction}} may be attached.
0107     Alternatively a user defined plugin could perform this action.
0108 \end{enumerate}
0109 
0110 %=============================================================================
0111 \subsection{Thread related contexts}
0112 \label{sec:ddg4-thread-save context}
0113 %=============================================================================
0114 \noindent
0115 \DDG provides thread related context, which may be accessed or modified
0116 by user code. This context, the {\tts{Geant4Context}} and its sub-components,
0117 as discussed in Section~\ref{sec:ddg4-implementation-higher-level-components}
0118 are available as separate instances for each event and as such
0119 also independently for each worker thread. Hence, no user level locking of the 
0120 event context is necessary in any worker thread.
0121 
0122 %=============================================================================
0123 \subsection{Thread-Shared Components}
0124 \label{sec:ddg4-multi-threaded-shared-actions}
0125 %=============================================================================
0126 \noindent
0127 Some actions, though executed in the context of a single thread context 
0128 may only execute as singletons. An example would be a {\tts{GeneratorAction}},
0129 which read input events from file. Clearly the reading of data from
0130 file must be protected and the reading of one event in a given thread
0131 must finish, before the next thread may take over.
0132 Another example are data analysis components, which e.g. fill a histogram.
0133 Typically the filling mechanism of a histogram is not thread safe and hence must
0134 be protected.
0135 
0136 \noindent
0137 To solve such issues all actions, which may involve such shared 
0138 activities, a shared action is provided, which adopts a singleton
0139 instance and executes the relevant callbacks in a protected manner.
0140 The shared actions execute the user component in a thread safe envelope.
0141 
0142 \noindent
0143 Clearly no run- or event related state in such shared actions may be
0144 carried by the component object across callbacks. The action objects
0145 may not be aware of the event related context outside the callback.
0146 Default implementations for such shared actions exist for
0147 \begin{itemize}\itemcompact
0148 \item the {\tts{Geant4RunAction}}, where the calls to 
0149         {\tts{Geant4RunAction::begin}} and {\tts{Geant4RunAction::end}}
0150         are {\bf{globally}} locked and the sequential execution of 
0151         the entire sequence is ensured;
0152 \item the {\tts{Geant4EventAction}},
0153 \item the {\tts{Geant4TrackingAction}},
0154 \item the {\tts{Geant4SteppingAction}} and
0155 \item the {\tts{Geant4StackingAction}}.
0156 \end{itemize}
0157 In the latter cases the framework ensures thread safety, but does 
0158 not ensure the reentrant execution order of the entire sequence.
0159 
0160 \noindent
0161 {\bf{General Remark:}}
0162 \noindent
0163 Simple callbacks registered to the run-, event, etc.-actions cannot 
0164 be protected. These callbacks may under no circumstances use any 
0165 event related state information of the called object.
0166 
0167 %=============================================================================
0168 \subsection{Backwards- and Single-Thread-Compatibility}
0169 \label{sec:ddg4-multi-threading-backwards}
0170 %=============================================================================
0171 \noindent
0172 As in the single threaded mode of Geant4, also in the multi-threaded
0173 mode all user actions are called by an instance of the {\tts{G4RunManager}}
0174 or a sublass thereof, the {\tts{G4MTRunManager}}~\cite{bib:Geant4-multi-threading}.
0175 
0176 \noindent
0177 If the recommended actions in sub-section~\ref{sec:ddg4-multi-threading-introduction}
0178 are used to configure the Geant4 application, then in a rather transparent
0179 way both single-threaded and multi-threaded setups can coexist simply by 
0180 changing the concrete instance of the {\tts{G4RunManager}}. There is one
0181 single exception: The user initialization function
0182 {\tts{G4VUserActionInitialization::BuildForMaster()}} is {\bf{only}} executed
0183 in multi-threaded mode. For this reason, we deprecate the usage. Try
0184 to find solutions, without master specific setup using e.g. shared actions.
0185 
0186 %=============================================================================
0187 \subsection{Support for Python Setup in Multi-Threading Mode}
0188 \label{sec:ddg4-multi-threading-python}
0189 %=============================================================================
0190 \noindent
0191 The setup of \DDG in multi-threaded mode requires separate callbacks for 
0192 the global configuration (geometry, etc.) and the configuration of the worker 
0193 threads. In python this setup is performed within {\rm{python callable}}
0194 objects, which are either functions or member functions of objects.
0195 These functions may have arguments. The python specific configuration actions
0196 \begin{itemize}\itemcompact
0197 \item The user initialization action 
0198     {\tts{Geant4PythonInitialization}} allows to configure python callbacks
0199     for the master and the worker thread setup using the calls:
0200     \begin{code}
0201       /// Set the Detector initialization command
0202       void setMasterSetup(PyObject* callable, PyObject* args);
0203       /// Set the field initialization command
0204       void setWorkerSetup(PyObject* callable, PyObject* args);              \end{code}
0205      to be used in python as a call sequence within the master thread:
0206     \begin{code}
0207      init_seq = kernel.userInitialization(True)
0208      init_action = UserInitialization(kernel,'Geant4PythonInitialization/PyG4Init')
0209      init_action.setWorkerSetup(worker_setup_call, < worker_args > )
0210      init_action.setMasterSetup(master_setup_call, < master_args > )
0211      init_seq.adopt(init_action)                                            \end{code}
0212     The callback argument list $< worker\_args >$ and $< master\_args >$
0213     are python tuples containing all arguments expected by the callable objects
0214     $worker\_setup\_call$ and $master\_setup\_call$ respecyively.
0215     The class {\tts{Geant4PythonInitialization}} is a subclass of
0216     {\tts{Geant4UserInitialization}} and will call the provided functions
0217     according to the protocol explained earlier in this section.
0218     If a callback is not set, the corresponding actiion is not executed.
0219 \item The detector construction action 
0220     {\tts{Geant4PythonDetectorConstruction}} is the corresponding 
0221     python action to populate the detector construction sequencer.
0222     and supports three ccallbacks:
0223     \begin{code}
0224       /// Set the Detector initialization command
0225       void setConstructGeo(PyObject* callable, PyObject* args);
0226       /// Set the field initialization command
0227       void setConstructField(PyObject* callable, PyObject* args);
0228       /// Set the sensitive detector initialization command
0229       void setConstructSensitives(PyObject* callable, PyObject* args);    \end{code}
0230     to be used in python as call sequence within the master thread:
0231     \begin{code}
0232     init_seq = self.master().detectorConstruction(True)
0233     init_action = DetectorConstruction(self.master(),name_type)
0234     init_action.setConstructGeo(geometry_setup_call, < geometry_args > )
0235     init_action.setConstructField(field_setup_call, < field_args > )
0236     init_action.setConstructSensitives(sensitives_setup_call, < sensitives_args >)
0237     init_seq.adopt(init_action)                                           \end{code}
0238     If any of the three callback is not set, the corresponding actiion is not executed.
0239     Hereby are $geometry\_setup\_call$, $field\_setup\_call$ and $sensitives\_setup\_call$ 
0240     the callable objects to configure the geometry, the tracking field 
0241     and the sensitive detectors.
0242     $< geometry\_args >$, $< field\_args >$ and $< sensitives\_args >$ are 
0243     the corresponding callable arguments in the form of a python tuple object.   
0244 \end{itemize}
0245 
0246 \noindent
0247 All python callbacks are supposed to return the integer '1' on success.
0248 Any other return code is assumed to be failure.
0249 
0250 %=============================================================================
0251 \subsection{\DDG Multi-Threading Example}
0252 \label{sec:ddg4-multi-threading-example}
0253 %=============================================================================
0254 \begin{code}
0255 """
0256 
0257    DD4hep simulation example setup DDG4
0258    in multi-threaded mode using the python configuration
0259 
0260    @author  M.Frank
0261    @version 1.0
0262 
0263 """
0264 import os, time, DDG4
0265 
0266 def setupWorker(geant4):
0267   kernel = geant4.kernel()
0268   print '#PYTHON: +++ Creating Geant4 worker thread ....'
0269   print "#PYTHON:  Configure Run actions"
0270   run1 = DDG4.RunAction(kernel,'Geant4TestRunAction/RunInit')
0271     ...
0272   print "#PYTHON:  Configure Event actions"
0273   prt = DDG4.EventAction(kernel,'Geant4ParticlePrint/ParticlePrint')
0274   kernel.eventAction().adopt(prt)
0275     ...
0276   print "\n#PYTHON:  Configure I/O\n"
0277   evt_root = geant4.setupROOTOutput('RootOutput','CLICSiD_'+time.strftime('%Y-%m-%d_%H-%M'))
0278     ...
0279   gen = DDG4.GeneratorAction(kernel,"Geant4GeneratorActionInit/GenerationInit")
0280   kernel.generatorAction().adopt(gen)
0281   print "#PYTHON:  First particle generator: pi+"
0282   gen = DDG4.GeneratorAction(kernel,"Geant4IsotropeGenerator/IsotropPi+");
0283     ...
0284   print "#PYTHON:  Merge all existing interaction records"
0285   gen = DDG4.GeneratorAction(kernel,"Geant4InteractionMerger/InteractionMerger")
0286   kernel.generatorAction().adopt(gen)
0287   print "#PYTHON:  Finally generate Geant4 primaries"
0288   gen = DDG4.GeneratorAction(kernel,"Geant4PrimaryHandler/PrimaryHandler")
0289   kernel.generatorAction().adopt(gen)
0290   print "#PYTHON:  ....and handle the simulation particles."
0291   part = DDG4.GeneratorAction(kernel,"Geant4ParticleHandler/ParticleHandler")
0292   kernel.generatorAction().adopt(part)
0293 
0294   user = DDG4.Action(kernel,"Geant4TCUserParticleHandler/UserParticleHandler")
0295     ...
0296   part.adopt(user)
0297   print '#PYTHON: +++ Geant4 worker thread configured successfully....'
0298   return 1
0299   
0300 def setupMaster(geant4):
0301   kernel = geant4.master()
0302   print '#PYTHON: +++ Setting up master thread for ',kernel.NumberOfThreads,' workers.'
0303   return 1
0304 
0305 def setupSensitives(geant4):
0306   print "#PYTHON:  Setting up all sensitive detectors"
0307   geant4.printDetectors()
0308   print "#PYTHON:  First the tracking detectors"
0309   seq,act = geant4.setupTracker('SiVertexBarrel')
0310     ...
0311   print "#PYTHON:  Now setup the calorimeters"
0312   seq,act = geant4.setupCalorimeter('EcalBarrel')
0313     ...
0314   return 1
0315 
0316 def run():
0317   kernel = DDG4.Kernel()
0318   lcdd = kernel.lcdd()
0319   install_dir = os.environ['DD4hepINSTALL']
0320   DDG4.Core.setPrintFormat("%-32s %6s %s")
0321   kernel.loadGeometry("file:"+install_dir+"/DDDetectors/compact/SiD.xml")
0322   DDG4.importConstants(lcdd)
0323 
0324   kernel.NumberOfThreads = 3
0325   geant4 = DDG4.Geant4(kernel,tracker='Geant4TrackerCombineAction')
0326   print "#  Configure UI"
0327   geant4.setupCshUI()
0328 
0329   print "#  Geant4 user initialization action"
0330   geant4.addUserInitialization(worker=setupWorker, worker_args=(geant4,),
0331                                master=setupMaster,master_args=(geant4,))
0332   print "#  Configure G4 geometry setup"
0333   seq,act = geant4.addDetectorConstruction("Geant4DetectorGeometryConstruction/ConstructGeo")
0334 
0335   print "# Configure G4 sensitive detectors: python setup callback"
0336   seq,act = geant4.addDetectorConstruction("Geant4PythonDetectorConstruction/SetupSD",
0337                                            sensitives=setupSensitives,sensitives_args=(geant4,))
0338   print "# Configure G4 sensitive detectors: atach'em to the sensitive volumes"
0339   seq,act = geant4.addDetectorConstruction("Geant4DetectorSensitivesConstruction/ConstructSD")
0340 
0341   print "#  Configure G4 magnetic field tracking"
0342   seq,field = geant4.addDetectorConstruction("Geant4FieldTrackingConstruction/MagFieldTrackingSetup")
0343   field.stepper            = "HelixGeant4Runge"
0344   field.equation           = "Mag_UsualEqRhs"
0345   field.eps_min            = 5e-05 * mm
0346   ...
0347   print "#  Setup random generator"
0348   rndm = DDG4.Action(kernel,'Geant4Random/Random')
0349   rndm.Seed = 987654321
0350   rndm.initialize()
0351   print "#  Now build the physics list:"
0352   phys = geant4.setupPhysics('QGSP_BERT')
0353   geant4.run()
0354 
0355 if __name__ == "__main__":
0356   run()
0357 \end{code}
0358 
0359 \newpage