This lesson is being piloted (Beta version)

EIC Tutorial: Understanding the Simulation Output

Set up the Jupyter Notebook Environment

Overview

Teaching: 5 min
Exercises: 5 min
Questions
  • How to access simulation campaign output with python?

Objectives
  • Set up interactive python platform with Jupyter-notebook.

Set up Jupyter-notebook

Note: we will be using other standard python packages such as numpy and pandas, which are pre-installed on Colab.

Key Points

  • install uproot and xrootd


Introduction to the DD4hep simulation

Overview

Teaching: 25 min
Exercises: 15 min
Questions
  • Understand the inputs and outputs of the DD4hep simulation

Objectives
  • Event generation

  • Detector description

  • MCParticles and detector hits

  • Simulation campaign files

DD4hep simulation

This Geant4-based simualtion package propagates particles through magnetic field and materials. Particles and detector hits for each event are saved in the output rootfiles.

Input 1: Event generation

The collision event at ePIC, including the beam particles, vertices, and outgoing particles, are typically generated with a dedicated event generator, e.g. PYTHIA8 for specific physics channels. The outputs are provided to the DD4hep simulation in HEPMC3 format.

One can also use the DD4hep’s particle gun to generate outgoing particles with given vertex and distribution, see the previous tutorial on ddsim.

Input 2: Detector description

The ePIC detector description in DD4hep is maintained on github. On the bottom of each sub-detector compact file under epic/compact, the readout block specifies how the detector hits are saved in the output rootfile.

Below is an example from epic/compact/tracking/vertex_barrel.xml:

  <readouts>
    <readout name="VertexBarrelHits">
      <segmentation type="CartesianGridXY" grid_size_x="0.020*mm" grid_size_y="0.020*mm" />
      <id>system:8,layer:4,module:12,sensor:2,x:32:-16,y:-16</id>
    </readout>
  </readouts>

All hits from this silicon vertex barrel detector, including their position, energy deposit, time, will be stored under the branch VertexBarrelHits in output. Each detector hit also comes an assigned 64-bit cell ID, with the last 32 bits from right to left represents the hit localtion in a 0.020 x 0.020 mm mesh grid. This segmentation often represents the detector granularity (in this case, the silicon pixel sensor size) that will be used later for hit digitization.

Output

The event tree in the simulation output contains

Exercise 1.1: access simulation campaign rootfiles The simulation campaign website documents the available datasets and version information.

-Browse the directory For stand-alone xrdfs command, see the previous tutorials. Here we will proceed with the python interface:

from XRootD import client
# Create XRootD client
eic_server = 'root://dtn-eic.jlab.org/'
fs = client.FileSystem(eic_server)
# List directory contents
fpath      = '/work/eic2/EPIC/RECO/24.12.0/epic_craterlake/SINGLE/e-/10GeV/130to177deg/'
status, files = fs.dirlist(fpath)
# Print files
if status.ok:
  print(files.size)
    for entry in files:
        print(entry.name)
else:
    print(f"Error: {status.message}")

-Open a simulation campaign file

fname      = eic_server+fpath+'e-_10GeV_130to177deg.0307.eicrecon.tree.edm4eic.root'
tree_name  = "events"
# tree_name = "podio_metadata"
tree       = ur.open(fname)[tree_name]
print(f"Read {fname}:{tree_name}. \n {tree.num_entries} events in total")

Exercise 1.2: inspect available branches in a rootfile

  • use tree.keys(filter_name="*",recursive=False) to display all branches
  • extract a given branch to dataframe
    bname = "MCParticles" 
    df    = tree[bname].array(library="ak")
    df    = ak.to_dataframe(df)
    print(df)
    

Exercise 1.3: extract momentum distribution of primary electrons

# select electrons
from particle import Particle
part   = Particle.from_name("e-")
pdg_id = part.pdgid.abspid
condition1  = df["MCParticles.PDG"]==pdg_id
# select primary particles
condition2  = df["MCParticles.generatorStatus"]==1 
# extract momentum and plot
# all electrons
df_new = df[condition1]   
mom    = np.sqrt(df_new["MCParticles.momentum.x"]**2+df_new["MCParticles.momentum.y"]**2+df_new["MCParticles.momentum.z"]**2)
bins   = np.arange(0,20)
_      = plt.hist(mom,bins=bins,alpha=0.5)
# primary electrons
df_new = df[condition1&condition2]   
mom    = np.sqrt(df_new["MCParticles.momentum.x"]**2+df_new["MCParticles.momentum.y"]**2+df_new["MCParticles.momentum.z"]**2)
_      = plt.hist(mom,bins=bins,histtype="step", color='r')

Key Points

  • event generator –dd4hep–> simulated hits and particles


Reconstruction workflow

Overview

Teaching: 25 min
Exercises: 15 min
Questions
  • Understand the EICrecon workflow

Objectives
  • Hit digitization

  • data model

  • Reconstruction algorithms

Reconstruction workflow

The ePIC reconsutrction framework EICrecon is maintained on github. It process simulated hits from various detectors to reconstruct trajectory, PID, etc, and eventually reconstruct the simulated particle and physics observables at the vertex. In this section, we will use track reconstruction as an example. Please refer to the Lehigh reconstruction workfest presentations for reconstruction workflow of other systems.

Each reconstruction step involves 3 components:

Digitization

All simualted detector hits are digitized to reflect certain detector specs e.g. spatial and time resolution, and energy threshold. For example, the VertexBarrelHits from simulation are digitized through the SiliconTrackerDigi factory in EICrecon/src/detectors/BVTX/BVTX.cc:

      // Digitization
    app->Add(new JOmniFactoryGeneratorT<SiliconTrackerDigi_factory>(
        "SiBarrelVertexRawHits", // factory name
        {
          "VertexBarrelHits"  // input
        },
        {
          "SiBarrelVertexRawHits",  // outputs
          "SiBarrelVertexRawHitAssociations"
        },
        {
            .threshold = 0.54 * dd4hep::keV, // configurations
        },
        app
    ));

The actual algorithm locates at EICrecon/src/algorithms/digi/SiliconTrackerDigi.cc, with its input and output specified in SiliconTrackerDigi_factory.h:

    class SiliconTrackerDigi_factory : public JOmniFactory<SiliconTrackerDigi_factory, SiliconTrackerDigiConfig> {

    public:
        using AlgoT = eicrecon::SiliconTrackerDigi;
    private:
        std::unique_ptr<AlgoT> m_algo;

        PodioInput<edm4hep::SimTrackerHit> m_sim_hits_input {this};

        PodioOutput<edm4eic::RawTrackerHit> m_raw_hits_output {this};
        PodioOutput<edm4eic::MCRecoTrackerHitAssociation> m_assoc_output {this};

        ParameterRef<double> m_threshold {this, "threshold", config().threshold};
        ParameterRef<double> m_timeResolution {this, "timeResolution", config().timeResolution};
        ...

By comparing the two blocks of code above, we can see that the digitized hits, SiBarrelVertexRawHits, are stored in the data type RawTrackerHit that is defined in the edm4eic data model:

edm4eic::RawTrackerHit:
    Description: "Raw (digitized) tracker hit"
    Author: "W. Armstrong, S. Joosten"
    Members:
      - uint64_t          cellID      // The detector specific (geometrical) cell id from segmentation
      - int32_t           charge             
      - int32_t           timeStamp         

In addition, the one-to-one relation between the sim hit and its digitized hit is stored as an MCRecoTrackerHitAssociation object:

edm4eic::MCRecoTrackerHitAssociation:
    Description: "Association between a RawTrackerHit and a SimTrackerHit"
    Author: "C. Dilks, W. Deconinck"
    Members:
      - float                 weight        // weight of this association
    OneToOneRelations:
      - edm4eic::RawTrackerHit rawHit       // reference to the digitized hit
      - edm4hep::SimTrackerHit simHit       // reference to the simulated hit

which is filled in SiliconTrackerDigi.cc:

    auto hitassoc = associations->create();
    hitassoc.setWeight(1.0);
    hitassoc.setRawHit(item.second);
    hitassoc.setSimHit(sim_hit);

Exercise 2.1: please find other detector systems that use SiliconTrackerDigi for digitization

Track Reconstruction

By default, we use the Combinatorial Kalman Filter from the ACTS library to handle track finding and fitting. This happens in the CKFTracking factory.

Exercise 2.2: please find the inputs and outputs of CKFTracking, and draw a flow chart from CentralTrackerMeasurements to CentralTrackVertices.

Reconstruction output

Exercise 2.3: The vector member or relation of a given data collection is saved in a separate branch starts with “_”.

  • Please use
    tree.keys(filter_name="_CentralCKFTrajectories*", recursive=False)
    

    to list those members in CentralCKFTrajectories

  • for a given event, the vector member _CentralCKFTrajectories_measurementChi2 provides a list of chi2 for each meaurement hit respectively. If multiple trajectories are found for one event, you can use CentralCKFTrajectories.measurementChi2_begin to locate the start index of a given trajectory (subentry).

Exercise 2.4: CentralTrackerMeasurements saved all available space points for tracking as 2D meaurement attached to representing surfaces.

  • Please use the relation _CentralTrackerMeasurements_hits to trace back to the original detector hit collection (hint: use the collection ID lookup table), and obtain the 3D coordinate of the hit

What’s next

Key Points

  • simulated hits–EICrecon–> reconstructed quantities