Typically when producing MC with different final states, a separate JOs is used for each final state. This is used to ensure sufficient statistics in each final state, especially when they have small branching ratios. Furthermore, it avoids generating events that are not useful in your analysis.
In most cases when using MadGraph, a particular final state can be
defined simply through the generate
expression or the options for
the parton shower tool if the decay is performed there. Other
generators may not provide this option.
In some instances, however, it is not possible to select a particular final state in this way. In these cases, generator filters can be used to keep only events that meet certain criteria.
The generator filter logic is applied after event generation and decays
are done. Any events that fail the filters are discarded and are not
passed through the computationally expensive detector simulation and
reconstruction steps in MC production. This means that events that fail
the filter requirements count towards nevents
but not towards maxEvents
.
Often a combination of generator commands and filters can be used together to optimize MC sample production. Try to avoid relying too heavily on filters with very low efficiencies. This can be unnecessarily expensive in CPU hours when a less computationally expensive solution exists.
In this tutorial, you will be using a suboptimal combination of generator commands and filters to be able to easily see how to use filters. In an analysis scenario, the dielectron and dimuon final states could be created as separate samples using generator commands, in which case no filter would be needed.
A variety of generator filters are available for use. Most filters have names that intuitively describe their purpose. You can also use the header files to read their purpose and the corresponding source files to see the configurable properties and how the logic is implemented. Some instructions are provided in the package README.
The existing filters provide significant coverage of the possible use-cases that you might encounter. It may take some clever combination of filters to get your desired outcome. If there is no way to use the existing filters to produce your final state with a reasonably high efficiency, you can create a new filter following the examples of the existing filters.
If you have not already done so, change the generate
expression in
your JOs to
generate g g > lepton lepton q q
This refers to the lepton
multi-particle representation that you
defined on the previous page. If you did not define lepton
, you
will encounter an error when running the generation again.
This will give you inclusive leptoquark decays to electrons and muons.
Did you see an error that at the end says “Error detected in MadGraphControl process”? If you look a little further up in the log file, do you see “No particle lepton in model” in the log file?
Hint if no leptons are in the model
The `generate` expression above relies on having a `lepton` defined. You have to define it in your job options, just like you had to define `q` for quarks. You can do that with the line: ```python define lepton = e mu ``` at the end of the multi-particle definitions section.
In order to select events that have either two electrons or two muons
we will use xAODDecaysFinalStateFilter
that allows us to select the
decay mode of heavy particles such as the leptoquarks.
Please have a look at the
filter definition
to understand how it works. In particular, follow the logic associated
with the PDGAllowedParents
, NElectrons
and NMuons
properties.
To implement the filters, add the following lines to the bottom of the JOs:
# Apply filters to get the decays we want
# We want either two electrons or two muons
# that come from the decay of a leptoquark
# This is necessary for xAOD filters
include ("GeneratorFilters/CreatexAODSlimContainers.py")
createxAODSlimmedContainer("TruthGen",prefiltSeq)
prefiltSeq.xAODCnv.AODContainerName = 'GEN_EVENT'
# Import the filters and add them to the filter sequence
from GeneratorFilters.GeneratorFiltersConf import xAODDecaysFinalStateFilter
filtSeq += xAODDecaysFinalStateFilter("eeFilter")
filtSeq += xAODDecaysFinalStateFilter("mumuFilter")
# Set allowed parent PDG IDs
filtSeq.eeFilter.PDGAllowedParents = [9000005,-9000005]
filtSeq.mumuFilter.PDGAllowedParents = [9000005,-9000005]
# Set minimum number of allowed leptons
filtSeq.eeFilter.NElectrons = 2
filtSeq.mumuFilter.NMuons = 2
# Set the filter message levels to DEBUG so we can see what is happening
filtSeq.eeFilter.OutputLevel = DEBUG
filtSeq.mumuFilter.OutputLevel = DEBUG
# Implement the logic for passing the set of filters
filtSeq.Expression = "eeFilter or mumuFilter"
The GeneratorFilters package README suggests to always use the “include” files in your code; in this case, that would mean
include("GeneratorFilters/xAODDecaysFinalStateFilter_Common.py")
. That included file, also known as a job options fragment, sets up one instance of the filter. For this case we need two instances (one for electrons and one for muons), so we need to do the setup ourselves. Whenever you have to set things up yourself and see a crash, it’s a good idea to first check the example job options fragment to see if you are setting things up in the recommended way.
The filtSeq.Expression
line provides the logic for using multiple filters.
In this case, we want events to pass either the eeFilter
or the mumuFilter
as indicated by the or
statement. This is a very common approach to allow
multiple types of events and can be done with any number of filters. Alternatively,
you can require events to pass the criteria of multiple filters by using an
and
statement. If you need something more complex, you can use paretheses
to group logical statements (e.g. (a and b) or c
). If you are trying to add
extremely complicated logic, it might be better to simply add your own filter in
the GeneratorFilters package.
The messaging level of the filters is set to DEBUG
to provide information
in log.generate
to help show how the decisions are made.
Run the event generation again using the same Gen_tf.py
command.
If implemented correctly, the event generation should fail with the error:
Pythia8 ERROR Exceeded the max number of consecutive event failures.
The failure you have encountered is one of the most common issues when
implementing a generator filter. Look through log.generate
to find the
cause of this crash.
With a bit of searching, you should find a line that says:
PYTHIA Abort from Pythia::next: reached end of Les Houches Events File
As events are processed, messages such as the following are printed to indicate the progress:
AthenaEventLoopMgr INFO ===»> start processing event #25, run #100000 24 events processed so far «<=== … AthenaEventLoopMgr INFO ===»> done processing event #25, run #100000 25 events processed so far «<===
The final line before the error sheds light onto the issue:
AthenaEventLoopMgr INFO ===»> start processing event #111, run #100000 110 events processed so far «<===
MadGraph has generated 110 Les Houches events (from nevents
and the safety
factor of 1.1
), but clearly this is not sufficient. To fix this, we need to
increase the safety factor to account for the filter efficiency. An arbitrarily
large safety factor is computationally wasteful since the Les Houches events
are generated before the filters are applied. Use information in log.generate
to find the optimal safety factor.
Search for a message from Py:EvgenFilterSeq
that includes:
INFO Filter Efficiency
From this, you should see a filter efficiency of approximately 42%. From this, it can be inferred that the safety factor should be a bit larger than 2.4. Due to possible statistical variation in the event generation, it is wise to increase the safety factor somewhat. A value of 2.5 should be sufficient for this sample.
Update the safety factor and run the same Gen_tf.py
command again as well as
the derivation and validation steps to make sure that the filters are correctly
implemented.