From 64079b56ceed3953ebea8aa5f2aa7190db155c48 Mon Sep 17 00:00:00 2001 From: Oliver Lantwin Date: Wed, 7 Oct 2026 17:40:06 +0200 Subject: [PATCH 1/2] fix(layout)!: follow integration layout 2026-0.1 along the beam Move the subsystems downstream of the muon shield to the positions of the integration layout drawing SPSXXSHIP0002 version 2026-0.1 (EDMS 3287817 v1.1, 2026-09-08). The previous values came from the 2025-1 layout via the FairShip GDML and from EDMS 3309666 rev 0.3. - straw stations: mid-planes 84.22, 86.22, 93.22 and 95.22 m (+150 mm) - spectrometer magnet: slot mid-plane 89.72 m (+150 mm) - upstream background tagger: slot mid-plane 32.87 m (+150 mm) - timing detector: centre of the 96.14-96.60 m slot (+468 mm) - tracker-magnet marker moved with the stations The decay volume (its wall already starts at 33.12 m as in the CAD model), the calorimeter, the muon shield and the SND are unchanged. BREAKING CHANGE: subsystem positions change; any field map or digitisation constant tied to the old positions must be updated. Assisted-by: claude-code:claude-fable-5-1 --- src/SHiPGeometry.cpp | 21 ++++++++++++------- subsystems/Magnet/README.md | 2 +- subsystems/TimingDetector/README.md | 2 +- subsystems/Trackers/README.md | 4 ++-- .../include/Trackers/TrackersFactory.h | 21 ++++++++++--------- subsystems/Trackers/test_trackers.cpp | 8 +++---- subsystems/UpstreamTagger/README.md | 2 +- .../UpstreamTagger/UpstreamTaggerFactory.h | 2 +- tests/test_consistency.cpp | 8 +++---- 9 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/SHiPGeometry.cpp b/src/SHiPGeometry.cpp index e8fe3c64..2e2de6e1 100644 --- a/src/SHiPGeometry.cpp +++ b/src/SHiPGeometry.cpp @@ -65,12 +65,15 @@ GeoPhysVol* SHiPGeometryBuilder::build() { GeoTrf::Translate3D(0.0, 0.0, 28.95 * m)); // Build and place UpstreamTagger (sensitive scintillator slab) - // Z: 32.52 to 32.92 m → centre: 32.72 m + // Integration layout 2026-0.1 (EDMS 3287817 v1.1): 0.4 m slot from 32.67 + // to 33.07 m at the entrance of the decay volume. The 160 mm tile plane is + // placed inside that slot with its rear face flush with the decay-volume + // container (32.92 m), so it cannot sit exactly on the slot mid-plane. SHiPUBTManager ubtManager; UpstreamTaggerFactory upstreamTaggerFactory(materials); GeoVPhysVol* upstreamTagger = upstreamTaggerFactory.build(&ubtManager); placeChild(world, upstreamTagger, "/SHiP/upstream_tagger", 3, - GeoTrf::Translate3D(0.0, 0.0, 32.72 * m)); + GeoTrf::Translate3D(0.0, 0.0, 32.84 * m)); // Build and place DecayVolume // Z: 32.92 to 83.32 m → centre: 58.12 m @@ -81,25 +84,27 @@ GeoPhysVol* SHiPGeometryBuilder::build() { // Build and place Trackers (container with 4 stations). // The factory already handles internal positioning; place the container at - // its centre Z (average of station 1 and 4 centres). + // its centre Z (average of station 1 and 4 centres, integration layout + // 2026-0.1: station mid-planes at 84.22, 86.22, 93.22 and 95.22 m). TrackersFactory trackersFactory(materials); GeoPhysVol* trackers = trackersFactory.build(); - constexpr double trackersCentreZ = (84.07 + 95.07) / 2.0 * m; + constexpr double trackersCentreZ = (84.22 + 95.22) / 2.0 * m; placeChild(world, trackers, "/SHiP/trackers", 5, GeoTrf::Translate3D(0.0, 0.0, trackersCentreZ)); // Build and place Magnet - // Z: 87.07 to 92.07 m → centre: 89.57 m + // Integration layout 2026-0.1: 5 m slot with its mid-plane at 89.72 m. MagnetFactory magnetFactory(materials); GeoPhysVol* magnet = magnetFactory.build(); - placeChild(world, magnet, "/SHiP/magnet", 6, GeoTrf::Translate3D(0.0, 0.0, 89.57 * m)); + placeChild(world, magnet, "/SHiP/magnet", 6, GeoTrf::Translate3D(0.0, 0.0, 89.72 * m)); // Build and place TimingDetector - // Z: 95.902 m (from GDML reference) + // Integration layout 2026-0.1: 0.46 m slot from 96.14 to 96.60 m, placed + // at the slot centre. TimingDetectorFactory timingDetectorFactory(materials); GeoPhysVol* timingDetector = timingDetectorFactory.build(); placeChild(world, timingDetector, "/SHiP/timing_detector", 7, - GeoTrf::Translate3D(0.0, 0.0, 95.902 * m)); + GeoTrf::Translate3D(0.0, 0.0, 96.37 * m)); // Build and place Calorimeter (ECAL + HCAL). // The layer structure comes from CalorimeterConstants.h; the outer container diff --git a/subsystems/Magnet/README.md b/subsystems/Magnet/README.md index 905fdb1c..f6f283fa 100644 --- a/subsystems/Magnet/README.md +++ b/subsystems/Magnet/README.md @@ -21,7 +21,7 @@ SHiPMagnet (Air, 6500×8600×5000 mm) └─ CV_4 (Aluminium) at (-2600, 0, +1525) ``` -Position in world: z = 89570 mm. +Position in world: z = 89720 mm (mid-plane of the 87.22–92.22 m slot in integration layout 2026-0.1, EDMS 3287817 v1.1). ## Materials diff --git a/subsystems/TimingDetector/README.md b/subsystems/TimingDetector/README.md index 4dafbb2b..d88714a0 100644 --- a/subsystems/TimingDetector/README.md +++ b/subsystems/TimingDetector/README.md @@ -14,7 +14,7 @@ Timing_Detector (Air, 5500×6500×500 mm) 3 columns × 110 rows; z stagger = (row%2)·12 + (col%2)·90 mm ``` -Position in world: z = 95902 mm. +Position in world: z = 96370 mm (centre of the 96.14–96.60 m slot in integration layout 2026-0.1, EDMS 3287817 v1.1). ## Materials diff --git a/subsystems/Trackers/README.md b/subsystems/Trackers/README.md index 064f93d9..af1b9a7d 100644 --- a/subsystems/Trackers/README.md +++ b/subsystems/Trackers/README.md @@ -33,13 +33,13 @@ The spectrometer dipole between stations 2 and 3 is a separate subsystem ``` Station Z positions (centres): 84070, 86070, 93070, 95070 mm. -Position in world: centred at z = 89570 mm (average of stations 1 and 4). +Position in world: centred at z = 89720 mm (average of stations 1 and 4). Stations 1-2 are upstream of the magnet, stations 3-4 downstream. ## Tracker magnet `/SHiP/trackers/tracker_magnet` is an inert, air-filled marker volume for -the tracker magnet, centred at z = 86820 mm with a 460 mm Z extent. +the tracker magnet, centred at z = 86970 mm with a 460 mm Z extent. It is **not** a physically-scaled dipole. The spectrometer dipole proper is the separate `Magnet` subsystem (iron yoke + coils) occupying z = 87.07 to diff --git a/subsystems/Trackers/include/Trackers/TrackersFactory.h b/subsystems/Trackers/include/Trackers/TrackersFactory.h index efc4708c..c4dd85e8 100644 --- a/subsystems/Trackers/include/Trackers/TrackersFactory.h +++ b/subsystems/Trackers/include/Trackers/TrackersFactory.h @@ -19,10 +19,11 @@ class SHiPMaterials; * * Builds 4 straw tracking stations for the SHiP spectrometer. Station * envelopes and z-positions follow the GDML reference / subsystem_envelopes.csv: - * - Station 1: Z 83.57-84.57 m → centre 84.07 m - * - Station 2: Z 85.57-86.57 m → centre 86.07 m - * - Station 3: Z 92.57-93.57 m → centre 93.07 m - * - Station 4: Z 94.57-95.57 m → centre 95.07 m + * - Station 1: Z 83.72-84.72 m → centre 84.22 m + * - Station 2: Z 85.72-86.72 m → centre 86.22 m + * - Station 3: Z 92.72-93.72 m → centre 93.22 m + * - Station 4: Z 94.72-95.72 m → centre 95.22 m + * (integration layout 2026-0.1, EDMS 3287817 v1.1) * Station envelope (GDML statbox): half 3000 × 3430 × 500 mm. * * Each station envelope is filled with 4 stereo views. A view is a material @@ -78,12 +79,12 @@ class TrackersFactory { // // NOTE: this is NOT a physically-scaled dipole. The spectrometer dipole // proper is the separate Magnet subsystem (iron yoke + coils) occupying - // z = 87.07-92.07 m. The only free space inside the trackers container + // z = 87.22-92.22 m. The only free space inside the trackers container // and clear of that yoke is a ~0.5 m gap, so this marker is sized to fit // there. It exists so the tracker magnet has a named placeholder in the // geometry; simulation/field code can locate it by the name // "/SHiP/trackers/tracker_magnet". - static constexpr double s_trackerMagnetZ = 86820.0 * mm; ///< centre + static constexpr double s_trackerMagnetZ = 86970.0 * mm; ///< centre static constexpr double s_trackerMagnetHalfZ = 230.0 * mm; ///< half-depth private: @@ -98,10 +99,10 @@ class TrackersFactory { static constexpr double s_halfZ = 500.0 * mm; // 50 cm // Station Z positions (centres, from origin). - static constexpr double s_station1Z = 84070.0 * mm; // 84.07 m - static constexpr double s_station2Z = 86070.0 * mm; // 86.07 m - static constexpr double s_station3Z = 93070.0 * mm; // 93.07 m - static constexpr double s_station4Z = 95070.0 * mm; // 95.07 m + static constexpr double s_station1Z = 84220.0 * mm; // 84.22 m + static constexpr double s_station2Z = 86220.0 * mm; // 86.22 m + static constexpr double s_station3Z = 93220.0 * mm; // 93.22 m + static constexpr double s_station4Z = 95220.0 * mm; // 95.22 m // Container dimensions (spans all stations). static constexpr double s_containerHalfZ = (s_station4Z - s_station1Z) / 2.0 + s_halfZ; diff --git a/subsystems/Trackers/test_trackers.cpp b/subsystems/Trackers/test_trackers.cpp index 5d5d6872..195b6ba9 100644 --- a/subsystems/Trackers/test_trackers.cpp +++ b/subsystems/Trackers/test_trackers.cpp @@ -95,10 +95,10 @@ TEST_CASE("TrackersHasTrackerMagnet", "[trackers]") { REQUIRE(tm != nullptr); auto* box = dynamic_cast(tm->getLogVol()->getShape()); REQUIRE(box != nullptr); - // Span must stay clear of station 2 (ends 86570 mm) and the Magnet yoke - // (starts 87070 mm): 86570 <= centre ± halfZ <= 87070. + // Span must stay clear of station 2 (ends 86720 mm) and the Magnet slot + // (starts 87220 mm): 86720 <= centre ± halfZ <= 87220. const double centre = TrackersFactory::s_trackerMagnetZ; const double halfZ = box->getZHalfLength(); - CHECK(centre - halfZ >= 86570.0); - CHECK(centre + halfZ <= 87070.0); + CHECK(centre - halfZ >= 86720.0); + CHECK(centre + halfZ <= 87220.0); } diff --git a/subsystems/UpstreamTagger/README.md b/subsystems/UpstreamTagger/README.md index 80953749..6dcd209f 100644 --- a/subsystems/UpstreamTagger/README.md +++ b/subsystems/UpstreamTagger/README.md @@ -59,7 +59,7 @@ registered with `SHiPUBTManager`. Tile totals: fine 2 × 400 + 2 × 19 200 = 39 200; coarse 300 + 2 × 3 750 = 7 800; **47 000 tiles** in total. -Position in world: z = 32 720 mm (centre of the 32.52–32.92 m envelope). +Position in world: z = 32 840 mm (inside the 32.67–33.07 m slot of integration layout 2026-0.1, EDMS 3287817 v1.1, with the rear face flush with the decay-volume container at 32.92 m). ## Materials diff --git a/subsystems/UpstreamTagger/include/UpstreamTagger/UpstreamTaggerFactory.h b/subsystems/UpstreamTagger/include/UpstreamTagger/UpstreamTaggerFactory.h index b85d1b47..bc5df877 100644 --- a/subsystems/UpstreamTagger/include/UpstreamTagger/UpstreamTaggerFactory.h +++ b/subsystems/UpstreamTagger/include/UpstreamTagger/UpstreamTaggerFactory.h @@ -45,7 +45,7 @@ class SHiPUBTManager; * "/SHiP/upstream_tagger/..." names, mirroring the calorimeter bar layers; * sensitive-detector assignment is performed downstream by name pattern. * - * The container envelope (half 2200 × 3200 × 80 mm, centre Z = 32 720 mm) + * The container envelope (half 2200 × 3200 × 80 mm, centre Z = 32 840 mm) * is unchanged from the previous monolithic slab so the placement in * SHiPGeometry and the subsystem-envelope consistency checks still hold. */ diff --git a/tests/test_consistency.cpp b/tests/test_consistency.cpp index 2f243834..3b1518fa 100644 --- a/tests/test_consistency.cpp +++ b/tests/test_consistency.cpp @@ -182,11 +182,11 @@ TEST_CASE("ConsistencyTest.PositionsSanity", "[consistency]") { {"/SHiP/target", 432.5, 500.0}, {"/SHiP/muon_shield", 16763.3, 500.0}, {"/SHiP/neutrino_detector", 28950.0, 500.0}, - {"/SHiP/upstream_tagger", 32720.0, 500.0}, + {"/SHiP/upstream_tagger", 32840.0, 500.0}, {"/SHiP/decay_volume", 58120.0, 500.0}, - {"/SHiP/trackers", 89570.0, 500.0}, - {"/SHiP/magnet", 89570.0, 500.0}, - {"/SHiP/timing_detector", 95902.0, 500.0}, + {"/SHiP/trackers", 89720.0, 500.0}, + {"/SHiP/magnet", 89720.0, 500.0}, + {"/SHiP/timing_detector", 96370.0, 500.0}, {"/SHiP/calorimeter", 98320.0, 500.0}, }; From 787d58fd9ed4db4ace2b15c2d4150fe0d7b0c02e Mon Sep 17 00:00:00 2001 From: Oliver Lantwin Date: Sat, 17 Oct 2026 13:44:59 +0200 Subject: [PATCH 2/2] docs(layout): update the remaining positions for layout 2026-0.1 The Trackers README still gave the old station centres and magnet range, and the UpstreamTagger summary called its position unchanged although the centre moved to 32 840 mm; only the envelope dimensions are the same. Tighten the PositionsSanity tolerance to 50 mm for the four moved subsystems. At 500 mm the test also passed with the old layout. Assisted-by: Claude Code:claude-opus-5-5 --- subsystems/Trackers/README.md | 6 +++--- .../include/UpstreamTagger/UpstreamTaggerFactory.h | 6 +++--- tests/test_consistency.cpp | 12 +++++++----- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/subsystems/Trackers/README.md b/subsystems/Trackers/README.md index af1b9a7d..eb78fdac 100644 --- a/subsystems/Trackers/README.md +++ b/subsystems/Trackers/README.md @@ -32,7 +32,7 @@ The spectrometer dipole between stations 2 and 3 is a separate subsystem └─ /SHiP/trackers/tracker_magnet (Air, inert marker box) ``` -Station Z positions (centres): 84070, 86070, 93070, 95070 mm. +Station Z positions (centres): 84220, 86220, 93220, 95220 mm. Position in world: centred at z = 89720 mm (average of stations 1 and 4). Stations 1-2 are upstream of the magnet, stations 3-4 downstream. @@ -42,8 +42,8 @@ Stations 1-2 are upstream of the magnet, stations 3-4 downstream. the tracker magnet, centred at z = 86970 mm with a 460 mm Z extent. It is **not** a physically-scaled dipole. The spectrometer dipole proper is -the separate `Magnet` subsystem (iron yoke + coils) occupying z = 87.07 to -92.07 m. The only space inside the trackers container that is clear of both +the separate `Magnet` subsystem (iron yoke + coils) occupying z = 87.22 to +92.22 m. The only space inside the trackers container that is clear of both the straw stations and that yoke is the ~0.5 m gap between station 2 and the yoke, so the marker is sized and placed to fit there without overlap. diff --git a/subsystems/UpstreamTagger/include/UpstreamTagger/UpstreamTaggerFactory.h b/subsystems/UpstreamTagger/include/UpstreamTagger/UpstreamTaggerFactory.h index bc5df877..d73ded31 100644 --- a/subsystems/UpstreamTagger/include/UpstreamTagger/UpstreamTaggerFactory.h +++ b/subsystems/UpstreamTagger/include/UpstreamTagger/UpstreamTaggerFactory.h @@ -45,9 +45,9 @@ class SHiPUBTManager; * "/SHiP/upstream_tagger/..." names, mirroring the calorimeter bar layers; * sensitive-detector assignment is performed downstream by name pattern. * - * The container envelope (half 2200 × 3200 × 80 mm, centre Z = 32 840 mm) - * is unchanged from the previous monolithic slab so the placement in - * SHiPGeometry and the subsystem-envelope consistency checks still hold. + * The container envelope (half 2200 × 3200 × 80 mm) has the same dimensions + * as the previous monolithic slab, so the subsystem-envelope consistency + * checks still hold. SHiPGeometry places it at centre Z = 32 840 mm. */ class UpstreamTaggerFactory { public: diff --git a/tests/test_consistency.cpp b/tests/test_consistency.cpp index 3b1518fa..274d51fc 100644 --- a/tests/test_consistency.cpp +++ b/tests/test_consistency.cpp @@ -177,16 +177,18 @@ TEST_CASE("ConsistencyTest.PositionsSanity", "[consistency]") { double tolerance; // mm }; - // Centres as placed in SHiPGeometryBuilder::build() + // Centres as placed in SHiPGeometryBuilder::build(). The subsystems moved for + // integration layout 2026-0.1 use a 50 mm tolerance, below the smallest of + // those shifts (120 mm), so the old positions would fail the check. std::vector expected = { {"/SHiP/target", 432.5, 500.0}, {"/SHiP/muon_shield", 16763.3, 500.0}, {"/SHiP/neutrino_detector", 28950.0, 500.0}, - {"/SHiP/upstream_tagger", 32840.0, 500.0}, + {"/SHiP/upstream_tagger", 32840.0, 50.0}, {"/SHiP/decay_volume", 58120.0, 500.0}, - {"/SHiP/trackers", 89720.0, 500.0}, - {"/SHiP/magnet", 89720.0, 500.0}, - {"/SHiP/timing_detector", 96370.0, 500.0}, + {"/SHiP/trackers", 89720.0, 50.0}, + {"/SHiP/magnet", 89720.0, 50.0}, + {"/SHiP/timing_detector", 96370.0, 50.0}, {"/SHiP/calorimeter", 98320.0, 500.0}, };