Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ShipSoft/FairShip/llms.txt

Use this file to discover all available pages before exploring further.

FairShip builds the full SHiP detector geometry at the start of every simulation run. The geometry is constructed in Python via python/geometry_config.py, instantiated as ROOT detector modules in python/shipDet_conf.py, and then exported to a geo_{tag}.root file that every downstream step — reconstruction, analysis, alignment — reads back. Understanding how the geometry is configured and stored is essential for making consistent changes across the simulation chain.

The ShipGeo configuration object

All geometric parameters — target position, muon shield dimensions, decay volume boundaries, spectrometer field maps — are collected in a single Config object (an attribute-accessible Python dictionary defined in python/ShipGeoConfig.py). This object is created by geometry_config.create_config() at the start of run_simScript.py:
import geometry_config

ship_geo = geometry_config.create_config(
    Yheight=6.0,           # max vacuum tank height in metres
    strawDesign=10,        # 10 = steel frame (default), 4 = aluminium
    shieldName="TRY_2025", # muon shield geometry key
    DecayVolumeMedium="helium",  # or "vacuums"
    SND=True,
    SND_design=[2],        # 1=EmulsionTarget, 2=MTC+SiliconTarget
    TARGET_YAML="$FAIRSHIP/geometry/target_config.yaml",
)
After the Geant4 run completes, this configuration is serialised as a JSON string and written into geo_{tag}.root under the key ShipGeo by python/saveBasicParameters.py.

Output geometry files

Every simulation run produces two geometry-related files:
FileKey(s)Contents
geo_{tag}.rootFAIRGeomFull TGeoManager — all volumes, materials, and field regions as ROOT TGeo objects
geo_{tag}.rootShipGeoSerialised Config object (JSON) — all numeric parameters used to build the geometry
params_{tag}.root(FairRoot parameters)FairRoot runtime-database entries; required by ShipReco.py

Loading geometry in analysis

To access either the TGeo navigation tree or the parameter config in an analysis script:
import ROOT
from ShipGeoConfig import load_from_root_file

# Open the geometry file (read-only)
geo_file = ROOT.TFile.Open("geo_my-run.root", "read")

# Load the ShipGeo parameter config (works with both JSON and legacy pickle format)
ship_geo = load_from_root_file(geo_file, "ShipGeo")

# Access the TGeoManager for navigation
geom = geo_file.Get("FAIRGeom")
geom.GetTopVolume().Draw("ogl")

# Use numeric parameters directly
print("Target z0:", ship_geo.target.z0)
print("Decay volume z:", ship_geo.decayVolume.z)
print("Muon shield length:", ship_geo.muShield.length)
load_from_root_file accepts either a ROOT.TFile object or a string path, and transparently handles both the current JSON format and older pickled-object files.

Muon shield database

The muon shield geometry is defined by parametric magnet dimensions stored in the shield_db dictionary in python/geometry_config.py. Each entry describes the six magnet sections of the active muon shield:
shield_db = {
    "TRY_2025": {
        "hybrid": False,           # True = superconducting + normal-conducting hybrid
        "WithConstField": False,   # True = uniform field approximation
        "params": [
            # Each row: [gap, half-length, dXIn, dXOut, dYIn, dYOut,
            #            gapIn, gapOut, dZgapIn, dZgapOut,
            #            dXIn2, dXOut2, dZgapIn2, dZgapOut2, field_direction]
            [0, 115.5, 50.00, 50.00, 119.00, 119.00, 2.00, 2.00, ...],
            # ... (6 magnet sections total)
        ],
    },
}
Select the shield geometry with --shieldName in run_simScript.py. Currently TRY_2025 is the only supported entry.
The muon shield total length is computed automatically from the params array: sum(gap + 2 × half_length) for each magnet section. Adding a new shield design requires adding an entry to shield_db and extending the choices list in the argument parser.

Passive detector volumes

The following FairModule subclasses form the passive structural skeleton of the SHiP detector. They are registered with FairRunSim in python/shipDet_conf.py:

ShipCave

The experimental cavern. Positioned at the start of the muon shield. Geometry loaded from geometry/caveWithAir.geo. Sets the overall world volume for Geant4.

ShipMuonShield

The active muon shield. Receives shield_params from shield_db[shieldName]. The SetSNDSpace method carves a hole in the shield for the SND detector.

ShipTargetStation

The fixed target. Layer positions and materials read from geometry/target_config.yaml. Supports sliced tungsten targets and helium gaps between slices.

ShipMagnet

The spectrometer magnet(s). Multiple magnet instances can be placed at different z positions depending on the geometry design (magnetDesign parameter).
Additional active detector modules (straw tubes, veto system, SND, time detector, upstream tagger) are also added to the run by shipDet_conf.configure().

YAML-based subsystem configuration

Several subsystems are configured through YAML files in the geometry/ directory, which are resolved at runtime via the $FAIRSHIP environment variable:
FileSubsystem
geometry/target_config.yamlFixed target slices, materials, gaps
geometry/veto_config_helium.yamlDecay vessel geometry for helium fill
geometry/veto_config_vacuums.yamlDecay vessel geometry for vacuum fill
geometry/strawtubes_config.yamlStraw tube tracker station parameters
geometry/MTC_config.yamlSND design 2 — Muon Tracker Chamber
geometry/SiliconTarget_config.yamlSND design 2 — Silicon Target
geometry/snd_config_old.yamlSND design 1 — legacy emulsion target
geometry/media.geoMaterial definitions for all volumes
The decay volume YAML is selected automatically based on the --vacuums / --helium flag:
# In geometry_config.py
veto_yaml = os.path.expandvars(f"$FAIRSHIP/geometry/veto_config_{DecayVolumeMedium}.yaml")

Key geometry parameters

The targetOpt comment in geometry_config.py documents the target geometry modes. In practice the target is now driven entirely by target_config.yaml, which specifies Nplates, plate thicknesses (L), inter-plate gaps (G), and materials (M) as lists:
# geometry/target_config.yaml (excerpt)
target:
  Nplates: 1
  N: [5]          # 5 slices in the single plate group
  L: [2.0]        # slice thickness in cm
  G: [0.5]        # gap between slices in cm
  M: ["tungsten"] # material name
The total target length and individual slice boundaries are computed by create_config() and stored in ship_geo.target.slices_length, ship_geo.target.slices_gap, and ship_geo.target.slices_material.

Environment variables

FAIRSHIP

Repository root directory. Used throughout FairShip to resolve paths to YAML configs, input files, and field maps (e.g. $FAIRSHIP/geometry/target_config.yaml). Set automatically by activate.sh in a pixi environment.

GEOMPATH

Geometry data directory for additional geometry assets. Some legacy code paths use this variable to locate field map and media files outside the main repository.

Geometry inspection tools

1

Print volume hierarchy

python macro/getGeoInformation.py \
    --geometry geo_ci-test.root \
    --level 2
Prints the TGeo volume tree to the specified depth. --level 1 shows only top-level modules; higher values expand into sub-volumes.
2

Check for overlaps

python python/experimental/check_overlaps.py \
    --geofile geo_ci-test.root
Runs ROOT’s TGeo overlap checker and prints any violations. The CI pipeline asserts that no overlaps are present:
pixi run ci-overlap-check
3

Enable overlap check during simulation

python macro/run_simScript.py --check-overlaps --tag overlap-test --dry-run
The --check-overlaps flag calls TGeoManager.CheckOverlaps(0.1) (0.1 mm tolerance) after the run, then performs a finer per-node check at 0.1 μm. Using --dry-run exits after geometry initialisation so no events need to be generated.
4

Inspect ShipGeo parameters

import ROOT
from ShipGeoConfig import load_from_root_file

geo_file = ROOT.TFile.Open("geo_my-run.root", "read")
ship_geo = load_from_root_file(geo_file, "ShipGeo")
print(ship_geo)  # prints all numeric parameters in sorted order

Geant4 physics and navigation configuration

The Geant4 VMC is configured in gconfig/g4Config.C. Key choices:
// gconfig/g4Config.C
TG4RunConfiguration* runConfiguration = new TG4RunConfiguration(
    "geomRoot",                         // ROOT geometry → Geant4 navigation
    "FTFP_BERT_HP_EMZ",                 // physics list: FTFP_BERT + high-precision neutrons + EM option Z
    "stepLimiter+specialCuts+specialControls",
    false,   // no special stacking
    false    // single-threaded
);
The geomRoot option means the TGeo geometry defined in Python is used directly for navigation — there is no separate Geant4-native geometry construction. Magnetic fields are set via VMC with the /mcDet/setIsLocalMagField true directive; the spectrometer field map is registered through python/geomGeant4.py’s addVMCFields() function.

Build docs developers (and LLMs) love