The muon shield is the most critical background-suppression element in SHiP. When 400 GeV protons hit the tungsten target they produce a dense cone of secondary muons — up to 10⁸ per spill — that would otherwise flood the downstream spectrometer. The shield consists of a sequence of magnetised iron magnets whose transverse field deflects muons of both signs out of the detector acceptance. It is passive (no readout) but dominates the experiment’s overall length and weight budget, so its geometry is highly optimised. TheDocumentation 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.
ShipMuonShield C++ class in passive/ builds the shield from a flat parameter vector read from the shield_db dictionary in python/geometry_config.py, and the ShipBFieldMap, ShipBellField, and ShipCompField classes in field/ provide the associated magnetic field descriptions.
C++ class: ShipMuonShield
The shield geometry lives in passive/ShipMuonShield.h and passive/ShipMuonShield.cxx. It inherits from FairRoot’s FairModule and overrides ConstructGeometry().
in_params into shield_params and computes nMagnets = in_params.size() / 15. If the vector length is not a multiple of 15 an error is logged.
SetSNDSpace
When SND design 2 (MTC) is active, the shield is asked to carve a rectangular hole matching the MTC detector footprint:
Parameter format: 15 numbers per magnet
Each row ofshield_db[name]["params"] encodes one magnet section as a list of exactly 15 floating-point numbers. The geometry engine unpacks them in the order shown below.
| Index | Symbol | Description |
|---|---|---|
| 0 | Zgap | Longitudinal gap (cm) upstream of this magnet |
| 1 | dZ (half-length) | Half-length of the magnet along beam axis (cm) |
| 2 | dXIn | Inner half-width in x at the entrance face (cm) |
| 3 | dXOut | Inner half-width in x at the exit face (cm) |
| 4 | dYIn | Inner half-height in y at the entrance face (cm) |
| 5 | dYOut | Inner half-height in y at the exit face (cm) |
| 6 | gapIn | Horizontal gap between left and right yoke halves at entrance (cm) |
| 7 | gapOut | Horizontal gap between left and right yoke halves at exit (cm) |
| 8 | ratio_yokeIn | Yoke cross-section ratio at entrance |
| 9 | ratio_yokeOut | Yoke cross-section ratio at exit |
| 10 | dY_yokeIn | Yoke y-half-height at entrance face (cm) |
| 11 | dY_yokeOut | Yoke y-half-height at exit face (cm) |
| 12 | midGapIn | Central midplane gap at entrance (cm) |
| 13 | midGapOut | Central midplane gap at exit (cm) |
| 14 | Bgoal | Target field strength (T); sign encodes field direction |
ShipMuonShield is the concatenation (flattened) of all rows:
Named shield configurations: shield_db
The shield_db dictionary in python/geometry_config.py stores named geometry variants. Each entry has three keys:
| Key | Type | Meaning |
|---|---|---|
hybrid | bool | Use a hybrid (superconducting + normal conducting) field configuration; passed as SC_key to ShipMuonShield |
WithConstField | bool | Use a constant-value field inside the magnet apertures instead of a bell-shaped or map-based field |
params | list[list[float]] | One sublist per magnet section, each with exactly 15 elements |
TRY_2025 — current baseline
Selecting a shield at runtime
Pass--shieldName to run_simScript.py:
geometry_config.create_config(shieldName="TRY_2025"). The function raises ValueError if the name is not present in shield_db.
Magnet z-positions
geometry_config.py pre-computes the z-centre of each magnet and stores it in c.muShield.Entrance:
configure_snd_mtc when zPosition == "auto" so the MTC sub-detector is aligned to the last magnet.
Magnetic field classes
- ShipBFieldMap
- ShipBellField
- ShipFieldMaker
Reads a 3-D field map from a ROOT file (distances in cm, fields in Tesla). Euler rotation angles and a global offset allow it to be positioned anywhere in the cavern.The spectrometer field map file is set in
geometry_config.py:Inspecting the shield geometry
After a simulation run, use the helper macro to print the geometry tree:TGeoManager::GetTopVolume() and recursively prints all daughter volumes down to depth 2, showing the ShipMuonShield assembly and its individual magnet sub-volumes (MagnetVolume_0, MagnetVolume_1, …).
Adding a new shield variant
shield_db["MY_SHIELD"] = {
"hybrid": False,
"WithConstField": False,
"params": [
# [Zgap, dZ, dXIn, dXOut, dYIn, dYOut, gapIn, gapOut,
# ratio_yokeIn, ratio_yokeOut, dY_yokeIn, dY_yokeOut, midGapIn, midGapOut, Bgoal]
[0, 100.0, 45.0, 45.0, 110.0, 110.0, 2.0, 2.0, 1.0, 1.0, 45.0, 45.0, 0.0, 0.0, 1.85],
# ... more magnet sections ...
],
}
The
--shieldName argument in macro/run_simScript.py has a choices restriction. Add your new name to the list so argparse accepts it:# macro/run_simScript.py — find this block and extend the choices list
parser.add_argument(
"--shieldName",
help="The name of the muon shield in the database to use.",
default="TRY_2025",
choices=["TRY_2025", "MY_SHIELD"], # add your name here
)