Newbie : Simulate events in the 4 detector concepts

Dear experts,

I am new to FCC-ee studies and i want to perform studies for FCC-ee at the Z-pole for a signal decay mode being Lb→ Lambda (ppi) gamma.

I would like to be able to run the production in the 4 detectors for the signal mode and some other physics backgrounds and background in general to understand the impact from trackers and calorimetry.

Following the physics workshop (2026) i understood it would be possible to generate events with the 4 detector designs and i would like to kindly ask if there is any place where i can look at to start generating the events i am interested in for the 4 options and have a simulation file which I can take from to look at the energy deposits- hits made by the signal or background particles in the trackers and calorimeter/ all sub-detectors.

Ultimately i will need to run some digitisation and reconstruction (which i understood exists but is maybe scattered a bit around in various packages) and do offline analysis to understand better the behavior with the calorimetry. Could some expert suggest what would be the best way to approach this study pointing me to some examples where a semi-complete pipeline is described?

Thanks a lot for the help

Renato

Dear Renato,

Thanks for reaching out and welcome to the FCCSW forum! As you correctly understood, we have Full Simulation in place for four FCC-ee detectors (ALLEGRO, CLD, IDEA, ILD), at different level of maturity, out of which you can get the SIM hits from Geant4. Regarding reconstruction, only CLD and ILD have complete chains (but the ILD one has to be validated for its FCC-ee flavor). IDEA and ALLEGRO have already some components but far from complete.

Here are the recipes to run the state of the art SIM-DIGI-RECO chains:

  • ALLEGRO
  • CLD
  • IDEA (still without crystals, we are working on the recipe with crystals)
  • ILD@FCCee, will come soon (meanwhile you can run the SIM step with this detector models)

The Geant4 simulation step is done with DDSIM, which can digest hepmc, hepevt, stdhep, edm4hep.

Here are some additional sources of documentations which you may need depending on your level of expertise in Key4hep: FCC Software .

Feel free to ask further questions if you face difficulties!

Cheers,

Brieuc

1 Like

Dear @brfranco , thanks a lot for the very helpful inputs which allowed me to already setup something on my side.

With the help of various AI to which i passed various tutorials, i ended up understandign that for my study, as first step i need to be able to produce my own signal decay, so i need to run ``k4run`` to run first a pythia step.

I am not an expert on this (simulation) so i was having a look a bit around to achieve what i want, which i doubt it’s the case anyway with what i will post later ( but at least is running successfully).

What i want to do is the following :
(ee → Z → bbar , have always one of the b to hadronize to a Lambdab ( so the other will do Lambdab-bar ) and then force one of the 2 to decay through my signal Lambdab→(ppi) gamma .
As starting point i wrote (p8_ee_Zbb_LambdaB_forced.cmd )

Beams:idA = 11
Beams:idB = -11
Beams:eCM = 91.2
WeakSingleBoson:ffbar2gmZ = on
23:onMode = off
23:onIfAny = 5 -5
! Optional mild baryon boost
StringFlav:probQQtoQ = 0.20
! Your forced decays (if not using EvtGen)
5122:onMode = off
5122:onIfMatch = 3122 22
5122:addChannel = 1 1.0 11 3122 22
-5122:onMode = off
-5122:onIfMatch = -3122 22
-5122:addChannel = 1 1.0 11 -3122 22
3122:onMode = off
3122:onIfMatch = 2212 -211
-3122:onMode = off
-3122:onIfMatch = -2212 211

Then i have my Lb2LambdaGamma.dec

# Lambda_b -> Lambda0 gamma decay
# The other b-quark decays inclusively (using DECAY.DEC defaults)
# Force Lambda_b radiative decay for analysis
Decay Lambda_b0
  1.0   Lambda0  gamma     PHSP;
Enddecay
Decay anti-Lambda_b0
  1.0   anti-Lambda0  gamma     PHSP;
Enddecay
# Lambda0 -> p pi decay
Decay Lambda0
  1.0   p+  pi-           PHSP;
Enddecay
Decay anti-Lambda0
  1.0   anti-p-  pi+      PHSP;
Enddecay
# All B mesons (B0, B+, Bs, Bc) will decay according to DECAY.DEC
# This provides the generic b-hadron decays for the other hemisphere
End

and my Generate_Lb.py file

from Gaudi.Configuration import INFO, DEBUG
from Configurables import (
ApplicationMgr,
GenAlg,
PythiaInterface,
HepMCToEDMConverter,
IOSvc
)
ApplicationMgr().EvtSel           = ‘NONE’
# ApplicationMgr().HistogramPersist = False
ApplicationMgr().EvtMax           = 200000   # Oversize → filter later for signal
ApplicationMgr().OutputLevel      = INFO
# Pythia8 as signal provider
pythia = PythiaInterface(“PythiaInterface”)
pythia.pythiacard = “p8_ee_Zbb_LambdaB_forced.cmd”
pythia.doEvtGenDecays     = True
pythia.UserDecayFile      = “Lb2LambdaGamma.dec”          # Your custom file (relative or absolute path)
pythia.EvtGenDecayFile    = “DECAY.DEC”   # NB: from wget  local
pythia.EvtGenParticleDataFile = “evt.pdl”      # NB: from wget local
# Optional: force reload or extra settings*
pythia.pythiaExtraSettings = [
“Init:showProcesses = on”,               # Print init summary
“Init:showMultipartonInteractions = on”
]
# Generator algorithm (wraps PythiaInterface)
gen = GenAlg(“Generator”)
gen.SignalProvider = pythia
# Convert HepMC → EDM4hep MCParticles
hepmc_converter = HepMCToEDMConverter(“HepMCToEDMConverter”)
hepmc_converter.hepmc.Path       = “hepmc”          # Input: HepMC GenEvent location
hepmc_converter.GenParticles.Path = “GenParticles”   # Output: EDM4hep MCParticle collection

# IOSvc for automatic EDM4hep output (writes ALL collections)
iosvc = IOSvc(“IOSvc”)
iosvc.Output = “ee_Zbb_Lb_Lgamma.edm4hep.root”  # Your file
# Execution sequence + add IOSvc as service
ApplicationMgr().TopAlg += [gen, hepmc_converter]
ApplicationMgr().ExtSvc += [iosvc]

Then i just run k4run generate_Lb.py , it runs successfully so it’s already a success for me. However i am not 100% sure i am generating things as i want ( or how would be suggested to do ). As i understood i need ee_Zbb_Lb_Lgamma.edm4hep.root to pass to various detectors setup to make some comparisons/studies. Is that correct?

Thanks a lot in advance
Renato

Hi Renato,

Good that you managed to generate your signal with Pythia8 + EvtGen! To validate your production, you could check the particle decay tree with EEDE for a few events and/or write a simple macro to print quantities from the MCParticles branch in your root file, in C++ or Python.

As i understood i need ee_Zbb_Lb_Lgamma.edm4hep.root to pass to various detectors setup to make some comparisons/studies. Is that correct?

That is correct. Since last year, ddsim supports the edm4hep format as input. Simulating the Geant4 detector response to your signal should be as simple as

ddsim –inputFiles YOUR_EDM4HEP_ROOT_FILE -N -1 ...

Mind that some recipes assume that the vertex smearing was not performed by Pythia, check that this is the case in you .cmd files (if you have something like MSTP(151)=1, the vertex smearing is ON).

Cheers,

Brieuc

Dear @brfranco , sorry to bother again.

I think i managed to setup Pythia to produce the events i wanted an i checked that everytime a bb has a Lb daughter i can keep the event.

In order to study signal candidates to build the analysis i have 100k signal events produced out of a 8% rate in Z->bb processes inclusive. So i used a script provided by Anja (working on a similar mode) to skim the .hepmc file as follows :

import pyhepmc
import numpy as np
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--input', '-i', type=str, help='Input HepMC file')
parser.add_argument('--output', '-o', type=str, help='Output HepMC file')
parser.add_argument('--bid', '-b', type=int, help='PDG ID of b hadron to filter for')
# we want the Lb->L gamma or Anti-Lb -> L gamma 
# this means 
args = parser.parse_args()

with open(args.input.replace("hepmc", "log"), "w") as f:
    reader = pyhepmc.ReaderAscii(args.input)
    writer = pyhepmc.WriterAscii(args.output)
    nevents = 0
    nevents_filtered = 0 
    nposID_Filter = 0 
    nnegID_Filter = 0 
    event = pyhepmc.GenEvent()
    while not reader.failed():
        reader.read_event(event)
        nevents += 1
        has_pid_of_interest = any(abs(p.pid) == args.bid for p in event.particles)
        if not has_pid_of_interest : continue
        # now only with pid of interest particles (Lb/Lbbar)
        nevents_filtered += 1
        writer.write_event(event)
        
        hasLb   = any(abs(p.pid) == args.bid and p.pid> 0 for p in event.particles)
        hasLbbar= any(abs(p.pid) == args.bid and p.pid< 0 for p in event.particles)
        nposID_Filter += int(any(abs(p.pid) == args.bid and p.pid> 0 for p in event.particles))
        nnegID_Filter += int(any(abs(p.pid) == args.bid and p.pid< 0 for p in event.particles))
                
        parent = np.where([p.pid == args.bid for p in event.particles])[0]
        for par in parent:
            for c in event.particles[par].children:
                mom = np.sqrt(c.momentum[0]**2+c.momentum[1]**2+c.momentum[2]**2)
                if mom > 45:
                    print(par, event.particles[par].pid, mom, c.pid, c.status)
    reader.close()
    writer.close()
    f.write(f"""
            Filtered: {nevents_filtered} decays in {nevents} events from input file = {args.input}, 
            PID_ASKED : {args.bid} 
            PID POS - PASS : {nposID_Filter}
            PID NEG - PASS : {nnegID_Filter}
            Output Saved To : {args.output}
    """)

Now i started with the IDEA detector and i am running over this file as in the links you sent me the following :

# get steering file
curl -L https://raw.githubusercontent.com/HEP-FCC/FCC-config/main/FCCee/FullSim/IDEA/IDEA_o1_v03/SteeringFile_IDEA_o1_v03.py \
     -o SteeringFile_IDEA_o1_v03.py


# RUN IT 
INPUT="../ee_Zbb_ecm91_LbLGamma.signalLbLGamma.hepmc"
OUTPUT="ee_Zbb_ecm91_LbLGamma.signalLbLGamma_ddsim_out.root"
ddsim --compactFile $K4GEO/FCCee/IDEA/compact/IDEA_o1_v03/IDEA_o1_v03.xml\
    --outputFile $OUTPUT\
    --skipNEvents 0\
    --numberOfEvents 1000\
    -I ../ee_Zbb_ecm91_LbLGamma.signalLbLGamma.hepmc\
    --steering SteeringFile_IDEA_o1_v03.py

The code runs but i am a bit puzzled that in 1 hour it seems to have executed and ran only over 8 events. Is that normal or am i mis-configuring something? Is there a way to get the GEANT4 step faster or is the baseline to use condor queues for this with 30-40 events per job?
Thanks in advance,
Renato