Configuring ParticleBomb

The ParticleBomb event generator, as its name suggests, can generate multiple particles coming from the same location, called an event vertex or simply vertex, much like a neutrino interaction. The generator is meant for training ML algorithms for generic data reconstruction tasks, so the generation follows a uniform distribution in the specified phasespace unlike a neam-neutrino simulation which is often colimated toward the direction of the beam. For instance, the vertex generated by the ParticleBomb is uniformly distributed within the specified volume. Generated particles follow a flat kinetic energy (or momentum, it’s a choice) distribution and produced in isotropic directions. The volume in which the vertex is sampled, the multiplicity of particles, the number of vertex to be sampled, the energy of particles, etc., etc. all need to be specified in the configuration file.

Let’s start with a simplest configuration that generates a mono-energetic muon.

config_text = '''

GeneratorMPV:         # Just a name to define a block, not important, can be anything
  NumEvent: [1,1]     # the number of times the interaction (vertex) is sampled
  NumParticle: [1,1]  # the number of particles to be generated per vertex
  XRange: [0,1000]    # The x-span [mm] of the volume to sample a vertex
  YRange: [0,1000]    # The y-span [mm] of the volume to sample a vertex
  ZRange: [0,1000]    # The z-span [mm] of the volume to sample a vertex
  TRange: [0,10]      # The time-span [ns] to sample a vertex
  Particles:          # A list of particles to be sampled is defined in this block
    -
      PDG:      [13]  # The list of PDG code to be sampled for a generation
      NumRange: [1,1] # The min and the max number of this particle that can be generated
      KERange:  [1,1] # The range of kinetic energy [GeV] to sample
      UseMom:   False # If True, the KERange is interpreted as a momentum
      Weight:   1     # Relative weight of likelihood to be generated (explained later)
'''

import yaml
from dlp_generator import create_generator

gen = create_generator( yaml.load(config_text, Loader=yaml.Loader) )


gen.PrintHierarchy(gen.Flatten(gen.Generate()))
Welcome to JupyROOT 6.22/09

The structure and ideas behind

It’s useful to introduce a concept of an event or an interaction. These are interchangebly used here, and they define an occurrence of particle(s) at a unique location, called vertex. A good example outside ParticleBomb is a neutrino interaction. The configuration of the ParticleBomb consists of two levels of attributes. The top level specifies parameters that govern interaction-level information. The lower level specifies parameters that govern particle-wise information.

In the above example, the top level is GeneratorMPV, which is a name of this particular configuration. The lower level part can be found under Particles:, and it provides particle-wise specification. As you can see, the lower level configuration takes a format of a list (i.e. it is under - below Particles:). We can provide more than one particle information in this block.

Next, we cover an overview of how the ParticleBomb event generator works and how attributes in each block play a role.

How ParticleBomb works

  1. Decide how many time to sample an event. Randomly set in the range of NumEvent. In the above case, [1,1] means it always produce 1 event.

  2. For each event, decide how many particles to sample. Randomly set in the range of NumParticle. In the above case, [1,1] means it always produce only 1 particle.

  3. For each event, decide where the vertex (x,y,z,t) should be. Randomly set in the range of XRange, YRange, ZRange, TRange.

Up to this point, all attributes concern the interaction-level information including how many particles to be generated in each interaction. The next steps concern a particle-level information and rely on the lower level part of the configuration.

  1. Decide which “particle” to sample. Here, a “particle” is an instance in the list of configurations defined under Particles: block. In the above example, we only have one particle (i.e. the list length is 1). If you have multiple entries (i.e. “particles”), then whether a certain particle is sampled or not concerns two parameters under each particle block.

  • NumRange specifies how often this particle must/can be sampled. These are specified by two integers, min (=must be sampled at least) and max (=cannot be sampled more than this). In the above example, [1,1] means this particle must be sampled at least once and cannot be sampled more than once.

  • Weight specifies how likely this particle is sampled when there are multiple particles defined in the lower block. Note that, at the interaction level, the total number of particles is already defined. Also, the min specified in NumRange is respected for all particles listed in the configuration (if this exceeds the number of particles allowed in an interaction, the generator throws an exception and stops). If there are more particles to be sampled after generating all particles with specified minimum count, then the generator use a weighted-random sampling to choose which particle to be generated. If you set the Weight factor larger than others, this particle is more likely to be generated beyond the minimum count.

  1. After the previous step, a particle information is generated. PDG is a list of types a subject particle can take. If multiple PDG codes are given, the generator randomly selects one of them. Next, the kinetic energy is sampled randomly within the range specified in KERange in GeV. If preferred to randomly sample in the momentum space, UseMom flag can be set to True.

In the example above, we specified NumEvent, NumParticle, and NumRange all to [1,1]. This means, every time, the generator produce 1 event, 1 particle per event, and at least and at most (=always exactly) 1 particle configuration is sampled. That configuration has PDG: [13], which means it’s always a muon and energy is sampled uniformly in the range of KERange: [1,1] GeV (haha yes, that means it’s always 1GeV).

Let’s go over some example configurations.

Example A: generating four particles

Let’s modify NumParticle so that it always produces 4 particles, and change the only particle’s configuration NumRange to allow up to 4 particles to be generated. This should produce two muons.

config_text = '''

GeneratorMPV:
  NumEvent: [1,1]
  NumParticle: [4,4]
  XRange: [0,1000]
  YRange: [0,1000]
  ZRange: [0,1000]
  TRange: [0,10]
  Particles:
    -
      PDG:      [13]
      NumRange: [1,4]
      KERange:  [1,1]
      UseMom:   False
      Weight:   1
'''

gen = create_generator( yaml.load(config_text, Loader=yaml.Loader) )

gen.PrintHierarchy(gen.Flatten(gen.Generate()))
Dumping hierarchy information for 4 particles...

  ---- Line 0 PDG 13 energy 1.10566 [GeV]

  ---- Line 1 PDG 13 energy 1.10566 [GeV]

  ---- Line 2 PDG 13 energy 1.10566 [GeV]

  ---- Line 3 PDG 13 energy 1.10566 [GeV]

Example B: including an electron in the choice

Let’s add an electron as another choice!

config_text = '''

GeneratorMPV:
  NumEvent: [1,1]
  NumParticle: [4,4]
  XRange: [0,1000]
  YRange: [0,1000]
  ZRange: [0,1000]
  TRange: [0,10]
  Particles:
    -
      PDG:      [13,11]
      NumRange: [1,4]
      KERange:  [1,1]
      UseMom:   False
      Weight:   1
'''

gen = create_generator( yaml.load(config_text, Loader=yaml.Loader) )

gen.PrintHierarchy(gen.Flatten(gen.Generate()))
Dumping hierarchy information for 4 particles...

  ---- Line 0 PDG 11 energy 1.00051 [GeV]

  ---- Line 1 PDG 11 energy 1.00051 [GeV]

  ---- Line 2 PDG 11 energy 1.00051 [GeV]

  ---- Line 3 PDG 13 energy 1.10566 [GeV]

Example C: add another particle configuration

Introduce another particle with PDG: [111] (a neutral pion). Let’s set the Weight: 0.2 so it is less likely to be produced compared to the first particle.

config_text = '''

GeneratorMPV:
  NumEvent: [1,1]
  NumParticle: [4,4]
  XRange: [0,1000]
  YRange: [0,1000]
  ZRange: [0,1000]
  TRange: [0,10]
  Particles:
    -
      PDG:      [13,11]
      NumRange: [1,4]
      KERange:  [1,1]
      UseMom:   False
      Weight:   1
    -
      PDG:      [111]
      NumRange: [1,4]
      KERange:  [1,1]
      UseMom:   False
      Weight:   0.2
'''

gen = create_generator( yaml.load(config_text, Loader=yaml.Loader) )

gen.PrintHierarchy(gen.Flatten(gen.Generate()))
Dumping hierarchy information for 4 particles...

  ---- Line 0 PDG 11 energy 1.00051 [GeV]

  ---- Line 1 PDG 13 energy 1.10566 [GeV]

  ---- Line 2 PDG 13 energy 1.10566 [GeV]

  ---- Line 3 PDG 13 energy 1.10566 [GeV]

A few special configuration parameters

I hope the above examples were helpful to learn how to use the ParticleBomb event generator. There are a few more special configuration parameters that have not been covered and they can be critical.

  • SEED … this sets the random number generator’s seed. -1 will be a time-seed, suited for physics studies. For debugging, in order to have a reproducible behavior, give a positive integer.

  • Debug … setting this True run the generator with more verbose mode, mainly for debugging purpose.

These two parameters should be specified at the root-level (see the example below). The last parameter is an important one and to be specified at the interaction configuration block.

  • AddParent … setting this True is recommended(!). When you generate multiple interactions where each interaction contains multiple particles, the output will be a flat list of all particles. It would be helpful if there can be a notion of “grouping” each interaction. When AddParent is set to True, a virtual parent particle is added to group those particles that belong to the same event.

Example D: generating a parent to group particles

Modify NumEvent to allow multiple interactions + enable AddParent in the interaction configuration block.

config_text = '''

SEED:      1
Debug:     False

GeneratorMPV:
  NumEvent: [2,3]
  NumParticle: [4,4]
  XRange: [0,1000]
  YRange: [0,1000]
  ZRange: [0,1000]
  TRange: [0,10]
  AddParent: True
  Particles:
    -
      PDG:      [13,11]
      NumRange: [1,4]
      KERange:  [1,1]
      UseMom:   False
      Weight:   1
    -
      PDG:      [111]
      NumRange: [1,4]
      KERange:  [1,1]
      UseMom:   False
      Weight:   0.2
'''

gen = create_generator( yaml.load(config_text, Loader=yaml.Loader) )

gen.PrintHierarchy(gen.Flatten(gen.Generate()))
Dumping hierarchy information for 10 particles...

  ---- Line 0 PDG 39 energy 4.42263 [GeV] ... 4 children particles
    |- Line 1 PDG 13 energy 1.10566 [GeV] ... parent 0
    |- Line 2 PDG 13 energy 1.10566 [GeV] ... parent 0
    |- Line 3 PDG 13 energy 1.10566 [GeV] ... parent 0
    |- Line 4 PDG 13 energy 1.10566 [GeV] ... parent 0

  ---- Line 5 PDG 39 energy 4.21234 [GeV] ... 4 children particles
    |- Line 6 PDG 11 energy 1.00051 [GeV] ... parent 5
    |- Line 7 PDG 13 energy 1.10566 [GeV] ... parent 5
    |- Line 8 PDG 13 energy 1.10566 [GeV] ... parent 5
    |- Line 9 PDG 11 energy 1.00051 [GeV] ... parent 5

Example E: include multiple interaction definitions

We can include two different kind of interactions. Let’s add a “cosmic-like” interactions, which we call GeneratorMPR, that throw in single particles (i.e. each interaction contain only 1 particle, likely muon, and have many instance of interactions). We don’t enable AddParent for the GeneratorMPR because we configure it to only create 1 particle per interaction (so no need to be grouped).

config_text = '''

SEED:      1
Debug:     False

GeneratorMPV:
  NumEvent: [2,3]
  NumParticle: [4,4]
  XRange: [0,1000]
  YRange: [0,1000]
  ZRange: [0,1000]
  TRange: [0,10]
  AddParent: True
  Particles:
    -
      PDG:      [13,11]
      NumRange: [1,4]
      KERange:  [1,1]
      UseMom:   False
      Weight:   1
    -
      PDG:      [111]
      NumRange: [1,4]
      KERange:  [1,1]
      UseMom:   False
      Weight:   0.2

GeneratorMPR:
  NumEvent: [1,10]
  NumParticle: [1,1]
  XRange: [0,1000]
  YRange: [0,1000]
  ZRange: [0,1000]
  TRange: [0,10]
  Particles:
    -
      PDG:      [13]
      NumRange: [0,10]
      KERange:  [0,1]
      UseMom:   False
      Weight:   5
    -
      PDG:      [2212]
      NumRange: [0,5]
      KERange:  [0,0.5]
      UseMom:   False
      Weight:   1
'''

gen = create_generator( yaml.load(config_text, Loader=yaml.Loader) )

gen.PrintHierarchy(gen.Flatten(gen.Generate()))
Dumping hierarchy information for 15 particles...

  ---- Line 0 PDG 39 energy 4.42263 [GeV] ... 4 children particles
    |- Line 1 PDG 13 energy 1.10566 [GeV] ... parent 0
    |- Line 2 PDG 13 energy 1.10566 [GeV] ... parent 0
    |- Line 3 PDG 13 energy 1.10566 [GeV] ... parent 0
    |- Line 4 PDG 13 energy 1.10566 [GeV] ... parent 0

  ---- Line 5 PDG 39 energy 4.21234 [GeV] ... 4 children particles
    |- Line 6 PDG 11 energy 1.00051 [GeV] ... parent 5
    |- Line 7 PDG 13 energy 1.10566 [GeV] ... parent 5
    |- Line 8 PDG 13 energy 1.10566 [GeV] ... parent 5
    |- Line 9 PDG 11 energy 1.00051 [GeV] ... parent 5

  ---- Line 10 PDG 13 energy 0.297561 [GeV]

  ---- Line 11 PDG 2212 energy 0.950469 [GeV]

  ---- Line 12 PDG 2212 energy 1.26875 [GeV]

  ---- Line 13 PDG 13 energy 1.00256 [GeV]

  ---- Line 14 PDG 13 energy 0.246352 [GeV]