Other simproc/Fifteen

Table Of Contents

Previous topic


Next topic


This Page

Daya Bay Links

Content Skeleton


Fifteen package successfully extends gaudi frame work to another level. It makes use of many advance features of dybgaudi, like AES, inputHeaders and using Stage tool to handle data transfer. Fifteen package is designed to handle the max complexity in simulation. It has sophisticated consideration on all kinds of possible physics scenario, event time information handling and data management. After two years’ usage and the feedback from users, it’s already absorbed a lot of ideas, like mixing pre-simulated events and reusing, and has gone into a mature stage.

Quick Start

After you get into nuwa environment, you are ready to start to generate your own simulation sample. In /NuWa-trunk-dbg/NuWa- trunk/dybgaudi/Tutorial/Sim15/aileron, after type in nuwa.py -n50 -o fifteen.root -m “FullChainSimple -T SingleLoader” > log it will generate 50 readouts from IBD and K40 events.

Simulation Stage

Simulation is separated into a few stages: Kinematic, Detector, Electronic, TrigRead and SingleLoader. Kinematic stage generates kinematic information, including time, position, particle and its momentum, etc. Detector stage is to geant4 to do detector response simulation, like scattering, cerenkov and scintillation light. At the end it will generate hit number (P.E.) in each PMT and hit information on RPC. Electronic simulation convert these physics hit into electronic signal. For example, hits on PMT are converted to pulses. TrigRead will do trigger judgement based on user setting, like NHit>10, which means number of fired PMTs must be above 10. When an event is triggered, it also produces readout. That means it will output ADC and TDC instead of a raw PMT pulse. The real data acquisition system works like a pipe line, it outputs its result one by one in time order. SingleLoader is designed for this purpose. The above description can be summarized in Fig. fig:stages



Simulation stages.

Stage Tool

Stage as explained in previous sections is an abstract concept in dividing all simulation components. For Fifteen package, stage tool physically separates each simulation tools, but also is a media in data transfer.

While synchronizing many generation sources, they generate many data in the same time – same execution cycle. For dybgaudi they are held by AES and inputHeaders. The time sequence in which they are generated is disordered. Stage tool is put in charge of managing all the processors in one simulation stage. it manages the execution of them, i.e. only run them when data is needed, and it caches the data from all processors, sorts them and output them in time order. A bad metaphor might be stage tool works like a central train station. It controls the incoming stream of all the trains to avoid possible crushing. It has some ability to let train stop for some period, then let them leave on time.


Gnrtr stands for Generator. For one type of events one generator needs to be specified. The type here is not limited to its physics generation mechanism. The same type of event in different volume or geometry structure may have different event rates, so they should be specified as two different Gnrtr. For example a type of radioactive background have different abundance in two types of material, then it will have different event rate.

While running Gnrtr will invoke each GenTools it owns, i.e. a real generator, timrator positioner, etc. User needs to specify all these tools for it.


One of DetSimProc’s main functions is to call the real simulation tool Geant4 through its Gaudi interface GiGa. The other important feature is to output each simheader in time order.

Imagine two GenHeaders’ times are very close: the first one in time is far away to any PMTs, while the second one is close to one PMT, it is possible that because of the time of light propagation, light from the second event will generate a PMT hit first. The chance of this to happen is small, but it is serious enough to cause whole simulation process to crush and all the following electronic and trigger logic to fail.

DetSimProc asks data input from simulation stage “Kinematic”. As promised by stage tool, all the kinematic information out of stage “Kinematic” are in time order, earliest to latest, no violation. Then DetSimProc take this advantage to ensure its output is also in time order. After DetSimProc got a GenHeader to simulate, it finished the detector simulation for that GenHeader first. That is it can know the earliest hit time of this SimHeader. DetSimProc keeps asking GenHeader from its lower stage and doing their detector simulation, until a time comparison test is success. DetSimProc caches all the information of processed GenHeaders and SimHeaders. It compares the earliest time of all SimHeaders and the time of the last GenHeader. When the time of a SimHeader is less than the last GenHeader, it claims safe for output for that SimHeader. Because the causality of event development, since the last GenHeader time is already bigger than the time of a previous SimHeader, any new simulated result SimHeader won’t go before this GenHeader, i.e. the previous SimHeader.


ElecSimProc maintains a pipeline of SimHits which are sorted by time. Normal geant4 simulated PMT and RPC hits from all kinds of sources are kept in this pipeline.

The first thing to do every time execute ElecSimProc is to find a time gap between two successive hits in this hit pipeline. The size of the gap is determined by DayaBay::preTimeTolerance + DayaBay::postTimeTolerance which should be actually corresponding to the time period where a prepulse or a afterpulse exist. Then in the real electronics simulation, prepulses and afterpulse can be inserted into these places. Certainly as explained in previous sections, when a time gap is found, the time of the gap stop must be less the current time of detector simulation stage. This is the only way to know there won’t be any hits from later simulation will fool into this gap.

The chunk of hits before the gap start are packed together and made a new hit collection, then sent to electronic simulation. So hits of all kinds of sources have a chance to mix and overlap. Electronics simulation tools will take over the job and each sub detector will process its part separately.

For each fast simualted MuonProphet muon, a fake hit is created and put into this pipeline. Instead of going into a full eletronics simulation, they are pushed into a fast electronics simulation. They are always 100 percent accepted even they didn’t passed trigger. Since they are also in the pipeline, their time is synchronized to the other geant4 simulated hits. User won’t obeserve a big delay between fast simulated muon and other events.


Trigger simulation and Readout simulation are combined together into one simulation stage, because they all needs input from electronic simulation, i.e. pulses information. In electronic simulation there is no such requirement that only some detector can join the simulation, so in the same way, trigger will work for all required detectors.

In principle the different delay from different electronic channel can flip the time order between different events, however the time gap requirement is at the scale of 10\mu s. It is believed that the possible time flip caused by electronic simulation will never go beyond that and there is no physics concern in simulating such a effect, so there is no complex time comparison in TrigReadProc.


Triggers and readouts found in ElecHeader are packed into one SimReadoutHeader. Certainly it is also possible that no trigger is found, since there are many low energy background events. SingleLoader caches all the triggers and readouts and output them one by one. When its own buffer is empty it will automatically ask data from lower stage.


The only chance that events of different type can overlap and produce some impact is in electronic simulation. Hits from different events which are close in time may not be distinguished in electronics. A correct mixing approaching with pre-simulated sample should happen before it goes into electronic simulation.

Another idea is to re-use some geant4 pre-simulated sample. Like for muon events, it has a high frequency and is extremely time-consuming. We care a lot more about its influence on its adjacent events than its own topology.

LoadingProc is created on this background. It accepts a pre-simulated file, which must contain SimHeaders, as an input stream and output them to Stage Detector tool.

At the same time it can be configured to reset the event rate, i.e. time of the generated events. It also simplify the process if any trigger or electronic simulation parameter needs to be adjusted, since don’t have to waste time to redo the longest geant4 simulation.

Algorithm Sim15

Algorithm Sim15 is a simple Gaudi algorithm which is inserted into Gaudi top algorithm list. It runs once every execution cycle. It sends out the initial request for generating MC events.

Customize Your Simulation Job

A General Example

This part will explain how exactly to write your own simulation script with Fifteen package. The example is from dybgaudi/Tutorial/Sim15/aileron/FullChainSimple.py which implements all the basic elements.

#!/usr/bin/env python
Configure the full chain of simulation from kinematics to readouts and
with multiple kinematics types mixed together.

    nuwa.py -n50 -o fifteen.root -m "FullChainSimple -T SingleLoader" > log

    -T: Optional stages are: Kinematic, Detector, Electronic, TrigRead or SingleLoader.

    More options are available like -w: wall clock starting time
                                    -F: time format
                                    -s: seed for IBD generator

    This is a copy of MDC09b.runIBD15.FullChain, however with less options,
    less generators configured and less truth info saved.

This is the first part of this script. In the first line it declares the running environment. What follows, quoted by “’, are a brief introduction of this script and usage of this script. It tells that this script will configure a full chain of simulation. It also includes a command line which can be used right away to start. Before looking into the script it also explains what arguments can be set and what are their options. These arguments will explained later.

Next I will follow the order of how this script is going to be executed in nuwa. Then it will bring us to the end of the script.

def configure(argv=[]):
    cfc = ConfigureFullChain(argv)

if __name__ == "__main__":

A python script is executable in a shell environment when it has

if __name__ == "__main__":

Like this FullChainSimple.py, you can directly type FullChainSimple.py in a tcsh or bash see what happens. It is often used to test the configuration needed before running nuwa.

When nuwa is loading a python module it will check whether it has a configure() method. User’s gaudi algorithms, services and tools’ should go into there. Here an object about Fifteen is created and some parameters “argv” are passed to it. Next we will see some details in Fifteen package configuration.

class ConfigureFullChain:
    def __init__(self,argv):
    def parse_args(self,argv):
    def configureKinematic(self):
    def configureDetector(self):
    def configureElectronic(self):
    def configureTrigRead(self):
    def configureSingleLoader(self):
    def configureSim15(self):
    def configure(self):

Now all the details are stripped out, and only the skeleton are left. ”...” indicates the real working code are omitted for a second. A class ConfigureFullChain is defined.


is always called when a data object is created. The useful interface invoked by nuwa will be configure(self). Note don’t confuse with the configure(argv=[]) mentioned previously.

Apparently it has configure functions for Kinematic, Detector, Electronic, TrigRead, SingleLoader simulation stages. It also can handle some parameters to be more user friendly in parse_args. The configureSim15 will create an algorithm called Sim15 which is the diver of the simulation job. Algorithm Sim15 sits on the top of all the simulation stages asking output.

Stage tools are firstly set up in the following.

def configure(self):

    from Stage import Configure as StageConfigure
    self.stage_cfg = StageConfigure()


     if stagedic[self.opts.top_stage]>=1:
     if stagedic[self.opts.top_stage]>=2:
    if stagedic[self.opts.top_stage]>=3:
     if stagedic[self.opts.top_stage]>=4:
    if stagedic[self.opts.top_stage]>=5:


According to the top simulation stage all required lower stage tools are created. For example if top stage is set to be Detector, then only stage tool Kinematic and Detector will be added. In the end the algorithm Sim15 is configured. Correspondingly Sim15 will ask data from stage tool Detector.

Next we will see the configuration of Gnrtr. In this example two generators, IBD and K40 are added to work at the same time.

def configureKinematic(self):
    from Gnrtr.IBD import EvtGenerator
    # from IBD import EvtGenerator
    ibd_gds = EvtGenerator(name     = 'IBD_gds',
                           seed     = self.opts.seed,
                           volume   = '/dd/Structure/AD/db-oil1',
                           strategy = 'Material',
                           material = 'GdDopedLS',
                           mode     = 'Uniform',
                           lifetime = 78.4*units.second, #daya bay site
                           wallTime = self.start_time_seconds)

    ibd_gds.ThisStageName = "Kinematic"
    self.stage_cfg.KinematicSequence.Members.append( ibd_gds )

 from Gnrtr.Radioact import Radioact
    k40_gds = Radioact(name       = 'K40_gds',
                       volume     = '/dd/Structure/AD/db-oil1',
                       nuclide    = 'K40',
                        abundance  = 3.01e17,
                       strategy   = 'Material',
                       material   = 'GdDopedLS',
                        start_time = self.start_time_seconds)

     k40_gds.ThisStageName = "Kinematic"
    self.stage_cfg.KinematicSequence.Members.append( k40_gds )

Basically only one line command is needed to specify one type of event. In the end their stage names are all assigned to be “Kinematic” and it generator algorithms are also added to stage tool Kinematic. i.e. the connection between stage tool and processors are built up. For details about generators’ configuration user can refer to previous sections, and they also need to have the knowledge of detector geometry and material.

def configureDetector(self):
    '''Configure the Detector stage'''

    import DetSim
    ds = DetSim.Configure(physlist=DetSim.physics_list_basic+DetSim.physics_list_nuclear,
                          use_push_algs = False)

    # QuantumEfficiency*CollectionEfficiency*QEScale = 0.24*1/0.9
    from DetSim.DetSimConf import DsPhysConsOptical
     optical = DsPhysConsOptical()
     #optical.UseScintillation = False
    optical.CerenPhotonScaleWeight = 3.5
    #optical.UseCerenkov = False
    optical.ScintPhotonScaleWeight = 3.5

     from DetSimProc.DetSimProcConf import DetSimProc
    dsp = DetSimProc()
    dsp.ThisStageName = "Detector"
     dsp.LowerStageName = "Kinematic"
     #dsp.OutputLevel = 2

     ds.historian(trackSelection="(pdg == 2112)",vertexSelection="(pdg == 2112)")

The above example shows how detector simulation part is configured. Usually DetSim works in a normal gaudi manner, here the option use_push_algs =
False will stop adding its to top algorithm list. The lines assigning stage names, lower stage and this stage, tells where the input data is from, and what the current stage is. Then this DetSimProc algorithm was added to the stage tool Detector.

In the rest the physics list is customized and both cerenkov and scintillation light are pre-scaled. From this example and the above one for generator it is already very obvious that Fifteen package just uses the simulation tools as others. It doesn’t create another set of tools. All setting of them can be directly moved to here.

Next we will see how electronic simulation is set up.

def configureElectronic(self):
    '''Configure the Electronics stage'''

    import ElecSim
    es = ElecSim.Configure(use_push_algs = False)

 from ElecSimProc.ElecSimProcConf import ElecSimProc
    esp = ElecSimProc()
    esp.ThisStageName = "Electronic"
 esp.LowerStageName = "Detector"
 #esp.OutputLevel = 2

    from ElecSim.ElecSimConf import EsIdealFeeTool
 feetool = EsIdealFeeTool()


There is nothing new here regarding about Fifteen package configuration, except that name of this stage is “Electronic” and lower stage is “Detector”. The simulation chain is setup in this way.

Here a non-linearity option is turn off to demonstrate how to configure the real working tool.

For completeness the configuration of TrigReadProc and SingleLoader are included.

def configureTrigRead(self):
    '''Configure the Trigger and Readout stage'''
    from TrigReadProc.TrigReadProcConf import TrigReadProc
 tsp = TrigReadProc()
 tsp.ThisStageName = "TrigRead"
    tsp.LowerStageName = "Electronic"
    #tsp.TrigTools = [...]
    #tsp.RoTools = [...]
    #tsp.OutputLevel = 2

def configureSingleLoader(self):
    '''Configure the SingleLoader stage'''
    from SingleLoader.SingleLoaderConf import SingleLoader
    sll = SingleLoader()
    sll.ThisStageName = "SingleLoader"
    sll.LowerStageName = "TrigRead"
    #sll.OutputLevel = 2

In the end the top pulling algorithm Sim15 is added to gaudi top algorithm list. Its only job is to bring up the initial request from top stage tool.

def configureSim15(self):
    from Stage.StageConf import Sim15

 from Gaudi.Configuration import ApplicationMgr
    theApp = ApplicationMgr()

Example for LoadingProc

LoadingProc is another input stream for SimHeader. So the configuration of LoadingProc should be a replacement for configureDetector in the above example. A working example can be found in Fifteen/LoadingProc/aileron/testAll.py

Here the configuration after stage Detector will not be repeated. Only the part for LoadingProc is shown. In that example two input files are specified. Each one is set to a new start time and a new event rate. Details are shown below. As usual the chain of simulation line are set up and input file are specified as expected.

def configureLoadingProc(self):
    from LoadingProc.LoadingProcConf import LoadingProc
    load = LoadingProc("LoadingProc.Oxygen18")
    load.StartSec = 0
    load.StartNano = 0
    #load.Distribution = "Exponential"
    load.Distribution = "Periodic"
    load.Rate = 1.0
    assembler_name = "Ox18Assem"
 load.HsAssembler = assembler_name
    load.OutputLevel = 2
     assem = Assembler(toolname = assembler_name,
                      filename = "input.root")

    # This and lower stage
    load.ThisStageName = "Detector"
    load.LowerStageName = ""
 # Add this processor to Gaudi sequencer

Reminders and Some Common Errors

AES must be used to use Fifteen to generate simulation sample. The number of events specified on the command line is the number of execution cycles. If asking readout as the final output, then the initial number of GenHeader varies depending on trigger efficiency.