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