From 610200dc1a384dbf9bd47c58e5a8d63a61482bd2 Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Tue, 30 Jun 2026 02:49:40 -0600 Subject: [PATCH 01/13] [MID] Add superconducting magnet/cryostat geometry to simulation --- .../MUON/MID/Simulation/src/Geometry.cxx | 116 ++++++++++++++++++ .../MUON/MID/Simulation/src/Materials.cxx | 29 +++++ Detectors/MUON/MID/Simulation/src/Materials.h | 5 +- 3 files changed, 149 insertions(+), 1 deletion(-) diff --git a/Detectors/MUON/MID/Simulation/src/Geometry.cxx b/Detectors/MUON/MID/Simulation/src/Geometry.cxx index 8452d4e5a7f49..10563c95289b2 100644 --- a/Detectors/MUON/MID/Simulation/src/Geometry.cxx +++ b/Detectors/MUON/MID/Simulation/src/Geometry.cxx @@ -26,6 +26,7 @@ #include #include #include +#include namespace o2 { @@ -344,10 +345,125 @@ TGeoVolume* createChamber(int iChamber) return chamber; } + +/// Magnet geometry variant selector +enum class MagnetVariant { + AluminiumWalls, ///< 11 cm cryostat, Al inner/outer walls + SteelWalls ///< 10 cm cryostat, Fe inner/outer walls +}; + +/// Creates the MID magnet/cryostat geometry +/// Port of GEANT4 simulation by Ian Perez Garcia (ICN-UNAM) +/// Reference: github.com/IanPG/MID-Geometry-Studies +void createMagnetGeometry(TGeoVolume& topVolume, + MagnetVariant variant = MagnetVariant::AluminiumWalls) +{ + const float R_cryostat_inner = 140.0f; + const float R_cryostat_outer = 200.0f; + const float R_coil_inner = 160.0f; + const float magnetHalfLength = 400.0f; + + const float thick_actual_coil = 4.8f; + const float thick_mli = 0.2f; + const float thick_coil_support = 2.0f; + + float thick_inner_wall; + float thick_outer_wall; + int wallMedium; + const char* variantTag; + + if (variant == MagnetVariant::AluminiumWalls) { + thick_inner_wall = 2.5f; + thick_outer_wall = 1.5f; + wallMedium = Medium::Aluminium; + variantTag = "Al"; + } else { + thick_inner_wall = 1.5f; + thick_outer_wall = 1.5f; + wallMedium = Medium::Iron; + variantTag = "Steel"; + } + + const float R_inner_wall_outer = R_cryostat_inner + thick_inner_wall; + const float R_coil_outer = R_coil_inner + thick_actual_coil; + const float R_mli_inner = R_coil_outer; + const float R_mli_outer = R_mli_inner + thick_mli; + const float R_coil_support_inner = R_mli_outer; + const float R_coil_support_outer = R_coil_support_inner + thick_coil_support; + const float R_outer_wall_inner = R_cryostat_outer - thick_outer_wall; + + // Mother volume (contains all cryostat layers) + auto magnetMotherShape = new TGeoTube(Form("MIDMagnetMother_%s_S", variantTag), + R_cryostat_inner, R_cryostat_outer, magnetHalfLength); + auto magnetMotherVol = new TGeoVolume(Form("MIDMagnetMother_%s", variantTag), + magnetMotherShape, assertMedium(Medium::Vacuum)); + magnetMotherVol->SetVisibility(kFALSE); + topVolume.AddNode(magnetMotherVol, 1, new TGeoTranslation(0., 0., -1155.)); + + // Layer 1: Inner wall (Al or Fe) + auto innerWallVol = new TGeoVolume(Form("MIDInnerWall_%s", variantTag), + new TGeoTube(Form("MIDInnerWall_%s_S", variantTag), + R_cryostat_inner, R_inner_wall_outer, magnetHalfLength), + assertMedium(wallMedium)); + innerWallVol->SetLineColor((variant == MagnetVariant::AluminiumWalls) ? kCyan+1 : kRed+1); + magnetMotherVol->AddNode(innerWallVol, 1, nullptr); + + // Layer 2: Inner vacuum gap + auto vacGap1Vol = new TGeoVolume(Form("MIDVacGap1_%s", variantTag), + new TGeoTube(Form("MIDVacGap1_%s_S", variantTag), + R_inner_wall_outer, R_coil_inner, magnetHalfLength), + assertMedium(Medium::Vacuum)); + magnetMotherVol->AddNode(vacGap1Vol, 1, nullptr); + + // Layer 3: Winding Pack (NbTi+Cu+Al, density=2.96 g/cm3) + auto coilVol = new TGeoVolume(Form("MIDCoil_%s", variantTag), + new TGeoTube(Form("MIDCoil_%s_S", variantTag), + R_coil_inner, R_coil_outer, magnetHalfLength), + assertMedium(Medium::WindingPack)); + coilVol->SetLineColor(kRed); + magnetMotherVol->AddNode(coilVol, 1, nullptr); + + // Layer 4: MLI - Multi-Layer Insulation (2mm Al) + auto mliVol = new TGeoVolume(Form("MIDMLI_%s", variantTag), + new TGeoTube(Form("MIDMLI_%s_S", variantTag), + R_mli_inner, R_mli_outer, magnetHalfLength), + assertMedium(Medium::Aluminium)); + mliVol->SetLineColor(kYellow); + magnetMotherVol->AddNode(mliVol, 1, nullptr); + + // Layer 5: A-5083 Support cylinder (20mm Al) + auto supportVol = new TGeoVolume(Form("MIDCoilSupport_%s", variantTag), + new TGeoTube(Form("MIDCoilSupport_%s_S", variantTag), + R_coil_support_inner, R_coil_support_outer, magnetHalfLength), + assertMedium(Medium::Aluminium)); + supportVol->SetLineColor(kBlue-7); + magnetMotherVol->AddNode(supportVol, 1, nullptr); + + // Layer 6: Outer vacuum gap + auto vacGap2Vol = new TGeoVolume(Form("MIDVacGap2_%s", variantTag), + new TGeoTube(Form("MIDVacGap2_%s_S", variantTag), + R_coil_support_outer, R_outer_wall_inner, magnetHalfLength), + assertMedium(Medium::Vacuum)); + magnetMotherVol->AddNode(vacGap2Vol, 1, nullptr); + + // Layer 7: Outer wall (Al or Fe) + auto outerWallVol = new TGeoVolume(Form("MIDOuterWall_%s", variantTag), + new TGeoTube(Form("MIDOuterWall_%s_S", variantTag), + R_outer_wall_inner, R_cryostat_outer, magnetHalfLength), + assertMedium(wallMedium)); + outerWallVol->SetLineColor((variant == MagnetVariant::AluminiumWalls) ? kCyan+1 : kRed+1); + magnetMotherVol->AddNode(outerWallVol, 1, nullptr); +} + void createGeometry(TGeoVolume& topVolume) { createMaterials(); + // Add magnet/cryostat geometry (Francisco Esquivel, June 2026) + printf("[MID] Calling createMagnetGeometry...\n"); + createMagnetGeometry(topVolume, MagnetVariant::AluminiumWalls); + printf("[MID] createMagnetGeometry done. Top volume nodes: %d\n", topVolume.GetNdaughters()); + // create and place the trigger chambers for (int iCh = 0; iCh < detparams::NChambers; iCh++) { diff --git a/Detectors/MUON/MID/Simulation/src/Materials.cxx b/Detectors/MUON/MID/Simulation/src/Materials.cxx index b6aeac75f8da8..d1d2fa6097b0a 100644 --- a/Detectors/MUON/MID/Simulation/src/Materials.cxx +++ b/Detectors/MUON/MID/Simulation/src/Materials.cxx @@ -169,6 +169,35 @@ void createMaterials() mgr.Mixture(kModuleName, ++imat, "Nomex", aNomex, zNomex, dNomex, -nNomex, wNomex); mgr.Medium(kModuleName, Medium::Nomex, "Nomex", imat, 0, fieldType, maxField, kMaxfd, kStemax, kDeemax, kEpsil, kStmin); + /// Iron (pure Fe) - absorber and steel cryostat walls + /// G4 equivalent: G4_Fe, density = 7.874 g/cm3 + const float kZIron_pure = 26.; + const float kAIron_pure = 55.845; + const float kDensIron = 7.874; + mgr.Material(kModuleName, ++imat, "Iron", kAIron_pure, kZIron_pure, kDensIron, 0., 0.); + mgr.Medium(kModuleName, Medium::Iron, "Iron", imat, 0, fieldType, maxField, + kMaxfd, kStemax, kDeemax, kEpsil, kStmin); + + /// WindingPack - superconducting coil (NbTi + Cu + Al) + /// Mass fractions: NbTi=8.10%, Cu=11.18%, Al=80.72%, density=2.96 g/cm3 + const float kZNiobium = 41.; + const float kANiobium = 92.90638; + const float kZTitanium = 22.; + const float kATitanium = 47.867; + const int nWP = 4; + float aWP[nWP] = {kANiobium, kATitanium, kACopper, kAAluminium}; + float zWP[nWP] = {kZNiobium, kZTitanium, kZCopper, kZAluminium}; + float wWP[nWP] = {0.0405, 0.0405, 0.1118, 0.8072}; + float dWP = 2.96; + mgr.Mixture(kModuleName, ++imat, "WindingPack", aWP, zWP, dWP, nWP, wWP); + mgr.Medium(kModuleName, Medium::WindingPack, "WindingPack", imat, 0, fieldType, maxField, + kMaxfd, kStemax, kDeemax, kEpsil, kStmin); + + /// Vacuum - thermal insulation gaps inside cryostat + mgr.Material(kModuleName, ++imat, "Vacuum", 1e-16, 1e-16, 1e-16, 0., 0.); + mgr.Medium(kModuleName, Medium::Vacuum, "Vacuum", imat, 0, fieldType, maxField, + kMaxfd, kStemax, kDeemax, kEpsil, kStmin); + } TGeoMedium* assertMedium(int imed) diff --git a/Detectors/MUON/MID/Simulation/src/Materials.h b/Detectors/MUON/MID/Simulation/src/Materials.h index 7461669f25e74..34e4fb42fe204 100644 --- a/Detectors/MUON/MID/Simulation/src/Materials.h +++ b/Detectors/MUON/MID/Simulation/src/Materials.h @@ -33,7 +33,10 @@ enum Medium { Copper, Mylar, Styrofoam, - Nomex + Nomex, + Iron, + WindingPack, + Vacuum }; // Return a pointer to the mid medium number imed. From 41d56f0552924484eaf756d6f6f62ecbf96ed29f Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Tue, 30 Jun 2026 03:03:55 -0600 Subject: [PATCH 02/13] Apply clang-format --- .../MUON/MID/Simulation/src/Geometry.cxx | 77 +++++++++---------- .../MUON/MID/Simulation/src/Materials.cxx | 7 +- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/Detectors/MUON/MID/Simulation/src/Geometry.cxx b/Detectors/MUON/MID/Simulation/src/Geometry.cxx index 10563c95289b2..793caf51965c3 100644 --- a/Detectors/MUON/MID/Simulation/src/Geometry.cxx +++ b/Detectors/MUON/MID/Simulation/src/Geometry.cxx @@ -345,7 +345,6 @@ TGeoVolume* createChamber(int iChamber) return chamber; } - /// Magnet geometry variant selector enum class MagnetVariant { AluminiumWalls, ///< 11 cm cryostat, Al inner/outer walls @@ -356,41 +355,41 @@ enum class MagnetVariant { /// Port of GEANT4 simulation by Ian Perez Garcia (ICN-UNAM) /// Reference: github.com/IanPG/MID-Geometry-Studies void createMagnetGeometry(TGeoVolume& topVolume, - MagnetVariant variant = MagnetVariant::AluminiumWalls) + MagnetVariant variant = MagnetVariant::AluminiumWalls) { const float R_cryostat_inner = 140.0f; const float R_cryostat_outer = 200.0f; - const float R_coil_inner = 160.0f; + const float R_coil_inner = 160.0f; const float magnetHalfLength = 400.0f; - const float thick_actual_coil = 4.8f; - const float thick_mli = 0.2f; + const float thick_actual_coil = 4.8f; + const float thick_mli = 0.2f; const float thick_coil_support = 2.0f; float thick_inner_wall; float thick_outer_wall; - int wallMedium; + int wallMedium; const char* variantTag; if (variant == MagnetVariant::AluminiumWalls) { thick_inner_wall = 2.5f; thick_outer_wall = 1.5f; - wallMedium = Medium::Aluminium; - variantTag = "Al"; + wallMedium = Medium::Aluminium; + variantTag = "Al"; } else { thick_inner_wall = 1.5f; thick_outer_wall = 1.5f; - wallMedium = Medium::Iron; - variantTag = "Steel"; + wallMedium = Medium::Iron; + variantTag = "Steel"; } - const float R_inner_wall_outer = R_cryostat_inner + thick_inner_wall; - const float R_coil_outer = R_coil_inner + thick_actual_coil; - const float R_mli_inner = R_coil_outer; - const float R_mli_outer = R_mli_inner + thick_mli; + const float R_inner_wall_outer = R_cryostat_inner + thick_inner_wall; + const float R_coil_outer = R_coil_inner + thick_actual_coil; + const float R_mli_inner = R_coil_outer; + const float R_mli_outer = R_mli_inner + thick_mli; const float R_coil_support_inner = R_mli_outer; const float R_coil_support_outer = R_coil_support_inner + thick_coil_support; - const float R_outer_wall_inner = R_cryostat_outer - thick_outer_wall; + const float R_outer_wall_inner = R_cryostat_outer - thick_outer_wall; // Mother volume (contains all cryostat layers) auto magnetMotherShape = new TGeoTube(Form("MIDMagnetMother_%s_S", variantTag), @@ -402,56 +401,56 @@ void createMagnetGeometry(TGeoVolume& topVolume, // Layer 1: Inner wall (Al or Fe) auto innerWallVol = new TGeoVolume(Form("MIDInnerWall_%s", variantTag), - new TGeoTube(Form("MIDInnerWall_%s_S", variantTag), - R_cryostat_inner, R_inner_wall_outer, magnetHalfLength), - assertMedium(wallMedium)); - innerWallVol->SetLineColor((variant == MagnetVariant::AluminiumWalls) ? kCyan+1 : kRed+1); + new TGeoTube(Form("MIDInnerWall_%s_S", variantTag), + R_cryostat_inner, R_inner_wall_outer, magnetHalfLength), + assertMedium(wallMedium)); + innerWallVol->SetLineColor((variant == MagnetVariant::AluminiumWalls) ? kCyan + 1 : kRed + 1); magnetMotherVol->AddNode(innerWallVol, 1, nullptr); // Layer 2: Inner vacuum gap auto vacGap1Vol = new TGeoVolume(Form("MIDVacGap1_%s", variantTag), - new TGeoTube(Form("MIDVacGap1_%s_S", variantTag), - R_inner_wall_outer, R_coil_inner, magnetHalfLength), - assertMedium(Medium::Vacuum)); + new TGeoTube(Form("MIDVacGap1_%s_S", variantTag), + R_inner_wall_outer, R_coil_inner, magnetHalfLength), + assertMedium(Medium::Vacuum)); magnetMotherVol->AddNode(vacGap1Vol, 1, nullptr); // Layer 3: Winding Pack (NbTi+Cu+Al, density=2.96 g/cm3) auto coilVol = new TGeoVolume(Form("MIDCoil_%s", variantTag), - new TGeoTube(Form("MIDCoil_%s_S", variantTag), - R_coil_inner, R_coil_outer, magnetHalfLength), - assertMedium(Medium::WindingPack)); + new TGeoTube(Form("MIDCoil_%s_S", variantTag), + R_coil_inner, R_coil_outer, magnetHalfLength), + assertMedium(Medium::WindingPack)); coilVol->SetLineColor(kRed); magnetMotherVol->AddNode(coilVol, 1, nullptr); // Layer 4: MLI - Multi-Layer Insulation (2mm Al) auto mliVol = new TGeoVolume(Form("MIDMLI_%s", variantTag), - new TGeoTube(Form("MIDMLI_%s_S", variantTag), - R_mli_inner, R_mli_outer, magnetHalfLength), - assertMedium(Medium::Aluminium)); + new TGeoTube(Form("MIDMLI_%s_S", variantTag), + R_mli_inner, R_mli_outer, magnetHalfLength), + assertMedium(Medium::Aluminium)); mliVol->SetLineColor(kYellow); magnetMotherVol->AddNode(mliVol, 1, nullptr); // Layer 5: A-5083 Support cylinder (20mm Al) auto supportVol = new TGeoVolume(Form("MIDCoilSupport_%s", variantTag), - new TGeoTube(Form("MIDCoilSupport_%s_S", variantTag), - R_coil_support_inner, R_coil_support_outer, magnetHalfLength), - assertMedium(Medium::Aluminium)); - supportVol->SetLineColor(kBlue-7); + new TGeoTube(Form("MIDCoilSupport_%s_S", variantTag), + R_coil_support_inner, R_coil_support_outer, magnetHalfLength), + assertMedium(Medium::Aluminium)); + supportVol->SetLineColor(kBlue - 7); magnetMotherVol->AddNode(supportVol, 1, nullptr); // Layer 6: Outer vacuum gap auto vacGap2Vol = new TGeoVolume(Form("MIDVacGap2_%s", variantTag), - new TGeoTube(Form("MIDVacGap2_%s_S", variantTag), - R_coil_support_outer, R_outer_wall_inner, magnetHalfLength), - assertMedium(Medium::Vacuum)); + new TGeoTube(Form("MIDVacGap2_%s_S", variantTag), + R_coil_support_outer, R_outer_wall_inner, magnetHalfLength), + assertMedium(Medium::Vacuum)); magnetMotherVol->AddNode(vacGap2Vol, 1, nullptr); // Layer 7: Outer wall (Al or Fe) auto outerWallVol = new TGeoVolume(Form("MIDOuterWall_%s", variantTag), - new TGeoTube(Form("MIDOuterWall_%s_S", variantTag), - R_outer_wall_inner, R_cryostat_outer, magnetHalfLength), - assertMedium(wallMedium)); - outerWallVol->SetLineColor((variant == MagnetVariant::AluminiumWalls) ? kCyan+1 : kRed+1); + new TGeoTube(Form("MIDOuterWall_%s_S", variantTag), + R_outer_wall_inner, R_cryostat_outer, magnetHalfLength), + assertMedium(wallMedium)); + outerWallVol->SetLineColor((variant == MagnetVariant::AluminiumWalls) ? kCyan + 1 : kRed + 1); magnetMotherVol->AddNode(outerWallVol, 1, nullptr); } diff --git a/Detectors/MUON/MID/Simulation/src/Materials.cxx b/Detectors/MUON/MID/Simulation/src/Materials.cxx index d1d2fa6097b0a..612a6ce132a35 100644 --- a/Detectors/MUON/MID/Simulation/src/Materials.cxx +++ b/Detectors/MUON/MID/Simulation/src/Materials.cxx @@ -173,15 +173,15 @@ void createMaterials() /// G4 equivalent: G4_Fe, density = 7.874 g/cm3 const float kZIron_pure = 26.; const float kAIron_pure = 55.845; - const float kDensIron = 7.874; + const float kDensIron = 7.874; mgr.Material(kModuleName, ++imat, "Iron", kAIron_pure, kZIron_pure, kDensIron, 0., 0.); mgr.Medium(kModuleName, Medium::Iron, "Iron", imat, 0, fieldType, maxField, kMaxfd, kStemax, kDeemax, kEpsil, kStmin); /// WindingPack - superconducting coil (NbTi + Cu + Al) /// Mass fractions: NbTi=8.10%, Cu=11.18%, Al=80.72%, density=2.96 g/cm3 - const float kZNiobium = 41.; - const float kANiobium = 92.90638; + const float kZNiobium = 41.; + const float kANiobium = 92.90638; const float kZTitanium = 22.; const float kATitanium = 47.867; const int nWP = 4; @@ -197,7 +197,6 @@ void createMaterials() mgr.Material(kModuleName, ++imat, "Vacuum", 1e-16, 1e-16, 1e-16, 0., 0.); mgr.Medium(kModuleName, Medium::Vacuum, "Vacuum", imat, 0, fieldType, maxField, kMaxfd, kStemax, kDeemax, kEpsil, kStmin); - } TGeoMedium* assertMedium(int imed) From f9b1f0f77f6dfc894e8f970be6601c7577f45b51 Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Tue, 7 Jul 2026 10:08:04 -0600 Subject: [PATCH 03/13] [MI3] Add superconducting magnet/cryostat geometry to ALICE3 MID simulation --- .../ALICE3/MID/simulation/src/Detector.cxx | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx index 0eaf401e40596..93413f834c779 100644 --- a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx @@ -86,6 +86,26 @@ void Detector::createMaterials() o2::base::Detector::Mixture(1, "POLYSTYRENE", aPolys, zPolys, dPolys, 2, wPolys); o2::base::Detector::Medium(1, "POLYSTYRENE", 1, 0, ifield, fieldm, tmaxfdPolys, stemaxPolys, deemaxPolys, epsilPolys, stminPolys); + + // Iron (pure Fe) - cryostat walls (Steel variant) + float aIron = 55.845; + float zIron = 26.; + float dIron = 7.874; + o2::base::Detector::Material(2, "IRON", aIron, zIron, dIron, 0., 0.); + o2::base::Detector::Medium(2, "IRON", 2, 0, ifield, fieldm, tmaxfdPolys, stemaxPolys, deemaxPolys, epsilPolys, stminPolys); + + // WindingPack - superconducting coil (NbTi + Cu + Al) + // Mass fractions: NbTi=8.10%, Cu=11.18%, Al=80.72%, density=2.96 g/cm3 (Arnaud report v0.2) + float aWP[4] = {92.90638, 47.867, 63.546, 26.982}; + float zWP[4] = {41., 22., 29., 13.}; + float wWP[4] = {0.0405, 0.0405, 0.1118, 0.8072}; + float dWP = 2.96; + o2::base::Detector::Mixture(3, "WINDINGPACK", aWP, zWP, dWP, 4, wWP); + o2::base::Detector::Medium(3, "WINDINGPACK", 3, 0, ifield, fieldm, tmaxfdPolys, stemaxPolys, deemaxPolys, epsilPolys, stminPolys); + + // Vacuum - thermal insulation gaps + o2::base::Detector::Material(4, "VACUUM", 1e-16, 1e-16, 1e-16, 0., 0.); + o2::base::Detector::Medium(4, "VACUUM", 4, 0, ifield, fieldm, tmaxfdPolys, stemaxPolys, deemaxPolys, epsilPolys, stminPolys); } void Detector::InitializeO2Detector() @@ -140,6 +160,46 @@ void Detector::createGeometry() for (auto& layer : mLayers) { layer.createLayer(vMID); } + + // Superconducting magnet/cryostat geometry + // Port of GEANT4 simulation by Ian Perez Garcia (ICN-UNAM) + // Reference: github.com/IanPG/MID-Geometry-Studies + // Aluminium walls variant: 11 cm total, Rmin=140 cm, Rmax=200 cm, half-length=400 cm + const float kRmin = 140.0f; + const float kRmax = 200.0f; + const float kHalfLen = 400.0f; + const float kWallInner = 2.5f; + const float kWallOuter = 1.5f; + const float kCoilInner = 160.0f; + const float kCoilThick = 4.8f; + const float kMLI = 0.2f; + const float kSupport = 2.0f; + + const float kR1 = kRmin + kWallInner; + const float kR2 = kCoilInner; + const float kR3 = kCoilInner + kCoilThick; + const float kR4 = kR3 + kMLI; + const float kR5 = kR4 + kSupport; + const float kR6 = kRmax - kWallOuter; + + auto* magnetMother = new TGeoVolume("MI3MagnetMother", + new TGeoTube("MI3MagnetMother_S", kRmin, kRmax, kHalfLen), + gGeoManager->GetMedium("MI3_POLYSTYRENE")); + gGeoManager->GetTopVolume()->AddNode(magnetMother, 1, new TGeoTranslation(0., 0., -1155.)); + + magnetMother->AddNode(new TGeoVolumeAssembly("MI3InnerWall"), 1, nullptr); + + magnetMother->AddNode(new TGeoVolumeAssembly("MI3VacGap1"), 1, nullptr); + + magnetMother->AddNode(new TGeoVolumeAssembly("MI3Coil"), 1, nullptr); + + magnetMother->AddNode(new TGeoVolumeAssembly("MI3MLI"), 1, nullptr); + + magnetMother->AddNode(new TGeoVolumeAssembly("MI3CoilSupport"), 1, nullptr); + + magnetMother->AddNode(new TGeoVolumeAssembly("MI3VacGap2"), 1, nullptr); + + magnetMother->AddNode(new TGeoVolumeAssembly("MI3OuterWall"), 1, nullptr); } void Detector::Reset() From b4c56ed70739c544de13ef1c033e145b6aa542db Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Mon, 13 Jul 2026 02:05:07 -0600 Subject: [PATCH 04/13] [ALICE3] Magnet: add WindingPack (NbTi+Cu+Al) coil material option --- .../MUON/MID/Simulation/src/Geometry.cxx | 115 ------------------ .../MUON/MID/Simulation/src/Materials.cxx | 28 ----- Detectors/MUON/MID/Simulation/src/Materials.h | 5 +- .../ALICE3/MID/simulation/src/Detector.cxx | 60 --------- .../Alice3DetectorsPassive/PassiveBaseParam.h | 3 +- .../Upgrades/ALICE3/Passive/src/Magnet.cxx | 18 ++- 6 files changed, 20 insertions(+), 209 deletions(-) diff --git a/Detectors/MUON/MID/Simulation/src/Geometry.cxx b/Detectors/MUON/MID/Simulation/src/Geometry.cxx index 793caf51965c3..8452d4e5a7f49 100644 --- a/Detectors/MUON/MID/Simulation/src/Geometry.cxx +++ b/Detectors/MUON/MID/Simulation/src/Geometry.cxx @@ -26,7 +26,6 @@ #include #include #include -#include namespace o2 { @@ -345,124 +344,10 @@ TGeoVolume* createChamber(int iChamber) return chamber; } -/// Magnet geometry variant selector -enum class MagnetVariant { - AluminiumWalls, ///< 11 cm cryostat, Al inner/outer walls - SteelWalls ///< 10 cm cryostat, Fe inner/outer walls -}; - -/// Creates the MID magnet/cryostat geometry -/// Port of GEANT4 simulation by Ian Perez Garcia (ICN-UNAM) -/// Reference: github.com/IanPG/MID-Geometry-Studies -void createMagnetGeometry(TGeoVolume& topVolume, - MagnetVariant variant = MagnetVariant::AluminiumWalls) -{ - const float R_cryostat_inner = 140.0f; - const float R_cryostat_outer = 200.0f; - const float R_coil_inner = 160.0f; - const float magnetHalfLength = 400.0f; - - const float thick_actual_coil = 4.8f; - const float thick_mli = 0.2f; - const float thick_coil_support = 2.0f; - - float thick_inner_wall; - float thick_outer_wall; - int wallMedium; - const char* variantTag; - - if (variant == MagnetVariant::AluminiumWalls) { - thick_inner_wall = 2.5f; - thick_outer_wall = 1.5f; - wallMedium = Medium::Aluminium; - variantTag = "Al"; - } else { - thick_inner_wall = 1.5f; - thick_outer_wall = 1.5f; - wallMedium = Medium::Iron; - variantTag = "Steel"; - } - - const float R_inner_wall_outer = R_cryostat_inner + thick_inner_wall; - const float R_coil_outer = R_coil_inner + thick_actual_coil; - const float R_mli_inner = R_coil_outer; - const float R_mli_outer = R_mli_inner + thick_mli; - const float R_coil_support_inner = R_mli_outer; - const float R_coil_support_outer = R_coil_support_inner + thick_coil_support; - const float R_outer_wall_inner = R_cryostat_outer - thick_outer_wall; - - // Mother volume (contains all cryostat layers) - auto magnetMotherShape = new TGeoTube(Form("MIDMagnetMother_%s_S", variantTag), - R_cryostat_inner, R_cryostat_outer, magnetHalfLength); - auto magnetMotherVol = new TGeoVolume(Form("MIDMagnetMother_%s", variantTag), - magnetMotherShape, assertMedium(Medium::Vacuum)); - magnetMotherVol->SetVisibility(kFALSE); - topVolume.AddNode(magnetMotherVol, 1, new TGeoTranslation(0., 0., -1155.)); - - // Layer 1: Inner wall (Al or Fe) - auto innerWallVol = new TGeoVolume(Form("MIDInnerWall_%s", variantTag), - new TGeoTube(Form("MIDInnerWall_%s_S", variantTag), - R_cryostat_inner, R_inner_wall_outer, magnetHalfLength), - assertMedium(wallMedium)); - innerWallVol->SetLineColor((variant == MagnetVariant::AluminiumWalls) ? kCyan + 1 : kRed + 1); - magnetMotherVol->AddNode(innerWallVol, 1, nullptr); - - // Layer 2: Inner vacuum gap - auto vacGap1Vol = new TGeoVolume(Form("MIDVacGap1_%s", variantTag), - new TGeoTube(Form("MIDVacGap1_%s_S", variantTag), - R_inner_wall_outer, R_coil_inner, magnetHalfLength), - assertMedium(Medium::Vacuum)); - magnetMotherVol->AddNode(vacGap1Vol, 1, nullptr); - - // Layer 3: Winding Pack (NbTi+Cu+Al, density=2.96 g/cm3) - auto coilVol = new TGeoVolume(Form("MIDCoil_%s", variantTag), - new TGeoTube(Form("MIDCoil_%s_S", variantTag), - R_coil_inner, R_coil_outer, magnetHalfLength), - assertMedium(Medium::WindingPack)); - coilVol->SetLineColor(kRed); - magnetMotherVol->AddNode(coilVol, 1, nullptr); - - // Layer 4: MLI - Multi-Layer Insulation (2mm Al) - auto mliVol = new TGeoVolume(Form("MIDMLI_%s", variantTag), - new TGeoTube(Form("MIDMLI_%s_S", variantTag), - R_mli_inner, R_mli_outer, magnetHalfLength), - assertMedium(Medium::Aluminium)); - mliVol->SetLineColor(kYellow); - magnetMotherVol->AddNode(mliVol, 1, nullptr); - - // Layer 5: A-5083 Support cylinder (20mm Al) - auto supportVol = new TGeoVolume(Form("MIDCoilSupport_%s", variantTag), - new TGeoTube(Form("MIDCoilSupport_%s_S", variantTag), - R_coil_support_inner, R_coil_support_outer, magnetHalfLength), - assertMedium(Medium::Aluminium)); - supportVol->SetLineColor(kBlue - 7); - magnetMotherVol->AddNode(supportVol, 1, nullptr); - - // Layer 6: Outer vacuum gap - auto vacGap2Vol = new TGeoVolume(Form("MIDVacGap2_%s", variantTag), - new TGeoTube(Form("MIDVacGap2_%s_S", variantTag), - R_coil_support_outer, R_outer_wall_inner, magnetHalfLength), - assertMedium(Medium::Vacuum)); - magnetMotherVol->AddNode(vacGap2Vol, 1, nullptr); - - // Layer 7: Outer wall (Al or Fe) - auto outerWallVol = new TGeoVolume(Form("MIDOuterWall_%s", variantTag), - new TGeoTube(Form("MIDOuterWall_%s_S", variantTag), - R_outer_wall_inner, R_cryostat_outer, magnetHalfLength), - assertMedium(wallMedium)); - outerWallVol->SetLineColor((variant == MagnetVariant::AluminiumWalls) ? kCyan + 1 : kRed + 1); - magnetMotherVol->AddNode(outerWallVol, 1, nullptr); -} - void createGeometry(TGeoVolume& topVolume) { createMaterials(); - // Add magnet/cryostat geometry (Francisco Esquivel, June 2026) - printf("[MID] Calling createMagnetGeometry...\n"); - createMagnetGeometry(topVolume, MagnetVariant::AluminiumWalls); - printf("[MID] createMagnetGeometry done. Top volume nodes: %d\n", topVolume.GetNdaughters()); - // create and place the trigger chambers for (int iCh = 0; iCh < detparams::NChambers; iCh++) { diff --git a/Detectors/MUON/MID/Simulation/src/Materials.cxx b/Detectors/MUON/MID/Simulation/src/Materials.cxx index 612a6ce132a35..b6aeac75f8da8 100644 --- a/Detectors/MUON/MID/Simulation/src/Materials.cxx +++ b/Detectors/MUON/MID/Simulation/src/Materials.cxx @@ -169,34 +169,6 @@ void createMaterials() mgr.Mixture(kModuleName, ++imat, "Nomex", aNomex, zNomex, dNomex, -nNomex, wNomex); mgr.Medium(kModuleName, Medium::Nomex, "Nomex", imat, 0, fieldType, maxField, kMaxfd, kStemax, kDeemax, kEpsil, kStmin); - /// Iron (pure Fe) - absorber and steel cryostat walls - /// G4 equivalent: G4_Fe, density = 7.874 g/cm3 - const float kZIron_pure = 26.; - const float kAIron_pure = 55.845; - const float kDensIron = 7.874; - mgr.Material(kModuleName, ++imat, "Iron", kAIron_pure, kZIron_pure, kDensIron, 0., 0.); - mgr.Medium(kModuleName, Medium::Iron, "Iron", imat, 0, fieldType, maxField, - kMaxfd, kStemax, kDeemax, kEpsil, kStmin); - - /// WindingPack - superconducting coil (NbTi + Cu + Al) - /// Mass fractions: NbTi=8.10%, Cu=11.18%, Al=80.72%, density=2.96 g/cm3 - const float kZNiobium = 41.; - const float kANiobium = 92.90638; - const float kZTitanium = 22.; - const float kATitanium = 47.867; - const int nWP = 4; - float aWP[nWP] = {kANiobium, kATitanium, kACopper, kAAluminium}; - float zWP[nWP] = {kZNiobium, kZTitanium, kZCopper, kZAluminium}; - float wWP[nWP] = {0.0405, 0.0405, 0.1118, 0.8072}; - float dWP = 2.96; - mgr.Mixture(kModuleName, ++imat, "WindingPack", aWP, zWP, dWP, nWP, wWP); - mgr.Medium(kModuleName, Medium::WindingPack, "WindingPack", imat, 0, fieldType, maxField, - kMaxfd, kStemax, kDeemax, kEpsil, kStmin); - - /// Vacuum - thermal insulation gaps inside cryostat - mgr.Material(kModuleName, ++imat, "Vacuum", 1e-16, 1e-16, 1e-16, 0., 0.); - mgr.Medium(kModuleName, Medium::Vacuum, "Vacuum", imat, 0, fieldType, maxField, - kMaxfd, kStemax, kDeemax, kEpsil, kStmin); } TGeoMedium* assertMedium(int imed) diff --git a/Detectors/MUON/MID/Simulation/src/Materials.h b/Detectors/MUON/MID/Simulation/src/Materials.h index 34e4fb42fe204..7461669f25e74 100644 --- a/Detectors/MUON/MID/Simulation/src/Materials.h +++ b/Detectors/MUON/MID/Simulation/src/Materials.h @@ -33,10 +33,7 @@ enum Medium { Copper, Mylar, Styrofoam, - Nomex, - Iron, - WindingPack, - Vacuum + Nomex }; // Return a pointer to the mid medium number imed. diff --git a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx index 93413f834c779..0eaf401e40596 100644 --- a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx @@ -86,26 +86,6 @@ void Detector::createMaterials() o2::base::Detector::Mixture(1, "POLYSTYRENE", aPolys, zPolys, dPolys, 2, wPolys); o2::base::Detector::Medium(1, "POLYSTYRENE", 1, 0, ifield, fieldm, tmaxfdPolys, stemaxPolys, deemaxPolys, epsilPolys, stminPolys); - - // Iron (pure Fe) - cryostat walls (Steel variant) - float aIron = 55.845; - float zIron = 26.; - float dIron = 7.874; - o2::base::Detector::Material(2, "IRON", aIron, zIron, dIron, 0., 0.); - o2::base::Detector::Medium(2, "IRON", 2, 0, ifield, fieldm, tmaxfdPolys, stemaxPolys, deemaxPolys, epsilPolys, stminPolys); - - // WindingPack - superconducting coil (NbTi + Cu + Al) - // Mass fractions: NbTi=8.10%, Cu=11.18%, Al=80.72%, density=2.96 g/cm3 (Arnaud report v0.2) - float aWP[4] = {92.90638, 47.867, 63.546, 26.982}; - float zWP[4] = {41., 22., 29., 13.}; - float wWP[4] = {0.0405, 0.0405, 0.1118, 0.8072}; - float dWP = 2.96; - o2::base::Detector::Mixture(3, "WINDINGPACK", aWP, zWP, dWP, 4, wWP); - o2::base::Detector::Medium(3, "WINDINGPACK", 3, 0, ifield, fieldm, tmaxfdPolys, stemaxPolys, deemaxPolys, epsilPolys, stminPolys); - - // Vacuum - thermal insulation gaps - o2::base::Detector::Material(4, "VACUUM", 1e-16, 1e-16, 1e-16, 0., 0.); - o2::base::Detector::Medium(4, "VACUUM", 4, 0, ifield, fieldm, tmaxfdPolys, stemaxPolys, deemaxPolys, epsilPolys, stminPolys); } void Detector::InitializeO2Detector() @@ -160,46 +140,6 @@ void Detector::createGeometry() for (auto& layer : mLayers) { layer.createLayer(vMID); } - - // Superconducting magnet/cryostat geometry - // Port of GEANT4 simulation by Ian Perez Garcia (ICN-UNAM) - // Reference: github.com/IanPG/MID-Geometry-Studies - // Aluminium walls variant: 11 cm total, Rmin=140 cm, Rmax=200 cm, half-length=400 cm - const float kRmin = 140.0f; - const float kRmax = 200.0f; - const float kHalfLen = 400.0f; - const float kWallInner = 2.5f; - const float kWallOuter = 1.5f; - const float kCoilInner = 160.0f; - const float kCoilThick = 4.8f; - const float kMLI = 0.2f; - const float kSupport = 2.0f; - - const float kR1 = kRmin + kWallInner; - const float kR2 = kCoilInner; - const float kR3 = kCoilInner + kCoilThick; - const float kR4 = kR3 + kMLI; - const float kR5 = kR4 + kSupport; - const float kR6 = kRmax - kWallOuter; - - auto* magnetMother = new TGeoVolume("MI3MagnetMother", - new TGeoTube("MI3MagnetMother_S", kRmin, kRmax, kHalfLen), - gGeoManager->GetMedium("MI3_POLYSTYRENE")); - gGeoManager->GetTopVolume()->AddNode(magnetMother, 1, new TGeoTranslation(0., 0., -1155.)); - - magnetMother->AddNode(new TGeoVolumeAssembly("MI3InnerWall"), 1, nullptr); - - magnetMother->AddNode(new TGeoVolumeAssembly("MI3VacGap1"), 1, nullptr); - - magnetMother->AddNode(new TGeoVolumeAssembly("MI3Coil"), 1, nullptr); - - magnetMother->AddNode(new TGeoVolumeAssembly("MI3MLI"), 1, nullptr); - - magnetMother->AddNode(new TGeoVolumeAssembly("MI3CoilSupport"), 1, nullptr); - - magnetMother->AddNode(new TGeoVolumeAssembly("MI3VacGap2"), 1, nullptr); - - magnetMother->AddNode(new TGeoVolumeAssembly("MI3OuterWall"), 1, nullptr); } void Detector::Reset() diff --git a/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h index 671f436aabe7b..1ce48ea908b4e 100644 --- a/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h +++ b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h @@ -26,7 +26,8 @@ namespace passive enum MagnetLayout : int { AluminiumStabilizer = 0, - CopperStabilizer = 1 + CopperStabilizer = 1, + WindingPack = 2 }; enum DetLayout : int { diff --git a/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx b/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx index e6c1171829bfc..53a8e8f25d352 100644 --- a/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx +++ b/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx @@ -98,6 +98,16 @@ void Alice3Magnet::createMaterials() matmgr.Medium("ALICE3_MAGNET", 1, "VACUUM", 1, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); matmgr.Medium("ALICE3_MAGNET", 9, "ALUMINIUM", 9, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); matmgr.Medium("ALICE3_MAGNET", 19, "COPPER", 19, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); + + // WindingPack: NbTi+Cu+Al composite (Arnaud report v0.2) + // Mass fractions: NbTi=8.10% (Nb=4.05%, Ti=4.05%), Cu=11.18%, Al=80.72% + // Density: 2.96 g/cm3 + float aWP[4] = {92.90638f, 47.867f, 63.546f, 26.982f}; + float zWP[4] = {41.f, 22.f, 29.f, 13.f}; + float wWP[4] = {0.0405f, 0.0405f, 0.1118f, 0.8072f}; + float dWP = 2.96f; + matmgr.Mixture("ALICE3_MAGNET", 29, "WINDINGPACK", aWP, zWP, dWP, 4, wWP); + matmgr.Medium("ALICE3_MAGNET", 29, "WINDINGPACK", 29, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); } void Alice3Magnet::ConstructGeometry() @@ -128,6 +138,7 @@ void Alice3Magnet::ConstructGeometry() } bool doCopperStabilizer = false; + bool doWindingPack = false; switch (passiveBaseParam.mLayout) { case o2::passive::MagnetLayout::AluminiumStabilizer: // Handled in the header file @@ -138,6 +149,10 @@ void Alice3Magnet::ConstructGeometry() mRestMaterialThickness += 2.2; // cm Add the Copper stabiliser LOG(debug) << "Alice 3 magnet: using Copper Stabilizer with thickness " << mRestMaterialThickness << " cm"; break; + case o2::passive::MagnetLayout::WindingPack: + doWindingPack = true; + LOG(debug) << "Alice 3 magnet: using WindingPack (NbTi+Cu+Al) coil"; + break; default: LOG(fatal) << "Unknown magnet layout " << passiveBaseParam.mLayout; break; @@ -152,6 +167,7 @@ void Alice3Magnet::ConstructGeometry() auto& matmgr = o2::base::MaterialManager::Instance(); auto kMedAl = matmgr.getTGeoMedium("ALICE3_MAGNET_ALUMINIUM"); auto kMedCu = matmgr.getTGeoMedium("ALICE3_MAGNET_COPPER"); + auto kMedWP = matmgr.getTGeoMedium("ALICE3_MAGNET_WINDINGPACK"); auto kMedVac = matmgr.getTGeoMedium("ALICE3_MAGNET_VACUUM"); // inner wrap @@ -169,7 +185,7 @@ void Alice3Magnet::ConstructGeometry() TGeoVolume* innerWrapVol = new TGeoVolume("innerWrap", innerLayer, kMedAl); TGeoVolume* innerVacuumVol = new TGeoVolume("innerVacuum", innerVacuum, kMedVac); - TGeoVolume* coilsVol = new TGeoVolume("coils", coilsLayer, kMedCu); + TGeoVolume* coilsVol = new TGeoVolume("coils", coilsLayer, doWindingPack ? kMedWP : kMedCu); TGeoVolume* restMaterialVol = new TGeoVolume("restMaterial", restMaterial, doCopperStabilizer ? kMedCu : kMedAl); TGeoVolume* outerVacuumVol = new TGeoVolume("outerVacuum", outerVacuum, kMedVac); TGeoVolume* outerWrapVol = new TGeoVolume("outerWrap", outerLayer, kMedAl); From 3554ddd461f98e97d98ab12bea2d84cb21cca8f3 Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Wed, 15 Jul 2026 07:37:21 -0600 Subject: [PATCH 05/13] [ALICE3] Magnet: improve WindingPack material documentation --- Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx b/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx index 53a8e8f25d352..f5272ca1d2ccd 100644 --- a/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx +++ b/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx @@ -99,7 +99,9 @@ void Alice3Magnet::createMaterials() matmgr.Medium("ALICE3_MAGNET", 9, "ALUMINIUM", 9, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); matmgr.Medium("ALICE3_MAGNET", 19, "COPPER", 19, 0, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); - // WindingPack: NbTi+Cu+Al composite (Arnaud report v0.2) + // WindingPack: effective composite material (NbTi:Cu:Al = 1:1:24 by area) + // Combines NbTi/Cu superconducting cable and Al stabiliser as a single effective medium + // Based on ICN-UNAM standalone simulation (I. Perez Garcia) // Mass fractions: NbTi=8.10% (Nb=4.05%, Ti=4.05%), Cu=11.18%, Al=80.72% // Density: 2.96 g/cm3 float aWP[4] = {92.90638f, 47.867f, 63.546f, 26.982f}; From 2d1f6f038f5b9638c50c809f40c264925ce954a7 Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Sun, 9 Aug 2026 04:21:30 -0600 Subject: [PATCH 06/13] =?UTF-8?q?ICN-UNAM:=20IanMagnet,=20IanAbsorber,=20I?= =?UTF-8?q?CNStepped=20MID=20layout=20=E2=80=94=200=20overlaps=20verified?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MID/base/include/MI3Base/MI3BaseParam.h | 3 +- .../include/MI3Simulation/MIDLayer.h | 9 +++- .../ALICE3/MID/simulation/src/Detector.cxx | 41 ++++++++++++++- .../ALICE3/MID/simulation/src/MIDLayer.cxx | 50 +++++++++++++------ .../Alice3DetectorsPassive/PassiveBaseParam.h | 6 ++- .../Upgrades/ALICE3/Passive/src/Absorber.cxx | 14 +++++- .../Upgrades/ALICE3/Passive/src/Magnet.cxx | 15 ++++++ 7 files changed, 115 insertions(+), 23 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/MID/base/include/MI3Base/MI3BaseParam.h b/Detectors/Upgrades/ALICE3/MID/base/include/MI3Base/MI3BaseParam.h index 913e27e85c207..18ba531d40ae3 100644 --- a/Detectors/Upgrades/ALICE3/MID/base/include/MI3Base/MI3BaseParam.h +++ b/Detectors/Upgrades/ALICE3/MID/base/include/MI3Base/MI3BaseParam.h @@ -26,7 +26,8 @@ namespace mi3 enum MIDLayout : int { StandardRadius = 0, - ReducedRadius = 1 + ReducedRadius = 1, + ICNStepped = 2 }; struct MIDBaseParam : public o2::conf::ConfigurableParamHelper { diff --git a/Detectors/Upgrades/ALICE3/MID/simulation/include/MI3Simulation/MIDLayer.h b/Detectors/Upgrades/ALICE3/MID/simulation/include/MI3Simulation/MIDLayer.h index 3900db72957ec..140e5534c95ff 100644 --- a/Detectors/Upgrades/ALICE3/MID/simulation/include/MI3Simulation/MIDLayer.h +++ b/Detectors/Upgrades/ALICE3/MID/simulation/include/MI3Simulation/MIDLayer.h @@ -92,7 +92,8 @@ class MIDLayer float staveLength = 500.f, float staveWidth = 50.f, float staveThickness = 0.5f, - int nModulesZ = 10); + int nModulesZ = 10, + int nBars = -1); void createStave(TGeoVolume* motherVolume); private: @@ -110,7 +111,7 @@ class MIDLayer public: MIDLayer() = default; - MIDLayer(int layerNumber, std::string layerName, float rInn, float length, int nstaves = 16); + MIDLayer(int layerNumber, std::string layerName, float rInn, float length, int nstaves = 16, float zOffset = 0.f, int nModulesZ = 10, float staveWidth = -1.f, int nBars = -1); void createLayer(TGeoVolume* motherVolume); private: @@ -118,8 +119,12 @@ class MIDLayer std::vector mStaves; float mRadius; float mLength; + float mZOffset; + float mStaveWidth; int mNumber; int mNStaves; + int mNModulesZ; + int mNBars; }; } // namespace o2::mi3 diff --git a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx index 0eaf401e40596..8eb7d5fcec1d9 100644 --- a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx @@ -20,6 +20,7 @@ #include "DetectorsBase/Stack.h" #include "ITSMFTSimulation/Hit.h" #include "MI3Simulation/Detector.h" +#include #include "MI3Base/MI3BaseParam.h" using o2::itsmft::Hit; @@ -125,14 +126,37 @@ void Detector::createGeometry() vMID->SetTitle(vstrng); // Build the MID - mLayers.resize(2); auto& midParam = MIDBaseParam::Instance(); const bool standardRadius = (midParam.mLayout == o2::mi3::MIDLayout::StandardRadius); if (standardRadius) { + mLayers.resize(2); mLayers[0] = MIDLayer(0, GeometryTGeo::composeSymNameLayer(0), 301.f, 500.f); mLayers[1] = MIDLayer(1, GeometryTGeo::composeSymNameLayer(1), 311.f, 520.f); // arbitrarily reduced to get multiple of 5.2f + } else if (midParam.mLayout == o2::mi3::MIDLayout::ICNStepped) { + // Ian Perez Garcia design (ICN-UNAM) — tesis §3.4.7 Geometria 8 + // 11 cm gap from absorber outer face to MID layer + // mLayer index is flat 0-5: even = physical layer 0, odd = physical layer 1 + // Module step: layer0=99.8cm (2x49.9), layer1=104cm (2x52=2xsumWidth) + // Central segment: Rmax_abso=290 -> Layer0=301, Layer1=311, nMod=6, semi-dz=299.4/312 at Z=0 + // External segments: Rmax_abso=265 -> Layer0=276, Layer1=286, nMod=2, semi-dz=99.8/104 at Z=+-400 + constexpr float kAbsGap = 11.f; + constexpr float kPitch = 10.f; + constexpr float kRCen0 = 290.f + kAbsGap; // 301 cm + constexpr float kRCen1 = kRCen0 + kPitch; // 311 cm + constexpr float kRExt0 = 265.f + kAbsGap; // 276 cm + constexpr float kRExt1 = kRExt0 + kPitch; // 286 cm + mLayers.resize(6); + // length = semi-longitud = nModulesZ x paso + // capa 0: paso=49.9, capa 1: paso=52 (sumWidth) + mLayers[0] = MIDLayer(0, "MIDLayer0_central", kRCen0, 299.4f, 16, 0.f, 6); // 6 mod x 49.9 + mLayers[1] = MIDLayer(1, "MIDLayer1_central", kRCen1, 312.f, 16, 0.f, 6); // 6 mod x 52 + mLayers[2] = MIDLayer(2, "MIDLayer0_forward", kRExt0, 99.8f, 16, +400.f, 2, -1.f, 21); // 2 mod x 49.9, nBars=21 for R=276 + mLayers[3] = MIDLayer(3, "MIDLayer1_forward", kRExt1, 104.f, 16, +405.f, 2); // 2 mod x 52, +5 offset to clear absorber at z=300 + mLayers[4] = MIDLayer(4, "MIDLayer0_backward", kRExt0, 99.8f, 16, -400.f, 2, -1.f, 21); // 2 mod x 49.9, nBars=21 for R=276 + mLayers[5] = MIDLayer(5, "MIDLayer1_backward", kRExt1, 104.f, 16, -405.f, 2); // 2 mod x 52, -5 offset to clear absorber at z=-300 } else { + mLayers.resize(2); mLayers[0] = MIDLayer(0, GeometryTGeo::composeSymNameLayer(0), 266.f, 500.f); mLayers[1] = MIDLayer(1, GeometryTGeo::composeSymNameLayer(1), 276.f, 520.f); } @@ -140,6 +164,21 @@ void Detector::createGeometry() for (auto& layer : mLayers) { layer.createLayer(vMID); } + // Register sensitive volumes by iterating all volumes + TObjArray* allVols = gGeoManager->GetListOfVolumes(); + TString sensorPattern = GeometryTGeo::getMIDSensorPattern(); + std::set registered; + for (int i = 0; i < allVols->GetEntries(); i++) { + TGeoVolume* v = (TGeoVolume*)allVols->At(i); + TString vname = v->GetName(); + // Match volumes whose name starts with MIDSensor + if (vname.Contains(sensorPattern) && registered.find(v) == registered.end()) { + AddSensitiveVolume(v); + registered.insert(v); + LOGP(info, "Adding MI3 Sensitive Volume {}", v->GetName()); + } + } + LOGP(info, "Total MI3 sensitive volumes registered: {}", registered.size()); } void Detector::Reset() diff --git a/Detectors/Upgrades/ALICE3/MID/simulation/src/MIDLayer.cxx b/Detectors/Upgrades/ALICE3/MID/simulation/src/MIDLayer.cxx index 7f214a2898459..2b42619ad4ecd 100644 --- a/Detectors/Upgrades/ALICE3/MID/simulation/src/MIDLayer.cxx +++ b/Detectors/Upgrades/ALICE3/MID/simulation/src/MIDLayer.cxx @@ -26,14 +26,22 @@ MIDLayer::MIDLayer(int layerNumber, std::string layerName, float rInn, float length, - int nstaves) : mName(layerName), + int nstaves, + float zOffset, + int nModulesZ, + float staveWidth, + int nBars) : mName(layerName), mRadius(rInn), mLength(length), + mZOffset(zOffset), + mStaveWidth(staveWidth), mNumber(layerNumber), - mNStaves(nstaves) + mNStaves(nstaves), + mNModulesZ(nModulesZ), + mNBars(nBars) { mStaves.reserve(nstaves); - LOGP(debug, "Constructing MIDLayer: {} with inner radius: {}, length: {} cm and {} staves", mName, mRadius, mLength, mNStaves); + LOGP(debug, "Constructing MIDLayer: {} with inner radius: {}, length: {} cm, {} staves and {} modules/stave", mName, mRadius, mLength, mNStaves, mNModulesZ); for (int iStave = 0; iStave < mNStaves; ++iStave) { mStaves.emplace_back(GeometryTGeo::composeSymNameStave(layerNumber, iStave), mRadius, @@ -41,8 +49,10 @@ MIDLayer::MIDLayer(int layerNumber, mNumber, iStave, mLength, - !layerNumber ? 59.8f : 61.75f, - 0.5f); + !(layerNumber % 2) ? 59.8f : 61.75f, + 0.5f, + mNModulesZ, + mNBars); } } @@ -54,7 +64,8 @@ MIDLayer::Stave::Stave(std::string staveName, float staveLength, float staveWidth, float staveThickness, - int nModulesZ) : mName(staveName), + int nModulesZ, + int nBars) : mName(staveName), mRadDistance(radDistance), mRotAngle(rotAngle), mLength(staveLength), @@ -64,17 +75,20 @@ MIDLayer::Stave::Stave(std::string staveName, mNumber(number), mNModulesZ(nModulesZ) { + // nBars=-1 uses default calibrated for standard radii + int effNBars = (nBars < 0) ? (!(mLayer % 2) ? 23 : 20) : nBars; + float moduleOffset = -effNBars * 5.2f / 2.f; // 5.2 = 2*barWidth + barSpacing // Staves are ideal shapes made of air including the modules, for now. - LOGP(debug, "\t\tConstructing MIDStave: {} layer: {} at angle {}", mName, mLayer, mRotAngle * TMath::RadToDeg()); + LOGP(debug, "\t\tConstructing MIDStave: {} layer: {} at angle {} nBars={}", mName, mLayer, mRotAngle * TMath::RadToDeg(), effNBars); mModules.reserve(nModulesZ); for (int iModule = 0; iModule < mNModulesZ; ++iModule) { mModules.emplace_back(GeometryTGeo::composeSymNameModule(mLayer, mNumber, iModule), mLayer, mNumber, iModule, - !mLayer ? 23 : 20, + effNBars, -staveLength, - !mLayer ? 49.9f : 61.75f); + !(mLayer % 2) ? 49.9f : 61.75f); } } @@ -106,8 +120,8 @@ MIDLayer::Stave::Module::Module(std::string moduleName, mStave, mNumber, iBar, - !mLayer ? -59.8f : -52.f, // offset - !mLayer ? 49.9f : 61.75f); // sensor length + -mNBars * 5.2f / 2.f, // moduleOffset derived from nBars + !(mLayer % 2) ? 49.9f : 61.75f); // sensor length } } @@ -136,9 +150,13 @@ MIDLayer::Stave::Module::Sensor::Sensor(std::string sensorName, void MIDLayer::createLayer(TGeoVolume* motherVolume) { - LOGP(debug, "Creating MIDLayer: {}", mName); + LOGP(debug, "Creating MIDLayer: {} at zOffset={} cm", mName, mZOffset); TGeoVolumeAssembly* layerVolume = new TGeoVolumeAssembly(mName.c_str()); - motherVolume->AddNode(layerVolume, 0); + if (mZOffset != 0.f) { + motherVolume->AddNode(layerVolume, 0, new TGeoTranslation(0, 0, mZOffset)); + } else { + motherVolume->AddNode(layerVolume, 0); + } for (auto& stave : mStaves) { stave.createStave(layerVolume); } @@ -172,7 +190,7 @@ void MIDLayer::Stave::Module::createModule(TGeoVolume* motherVolume) sensor.createSensor(moduleVolume); } TGeoCombiTrans* modTrans = nullptr; - if (!mLayer) { + if (!(mLayer % 2)) { modTrans = new TGeoCombiTrans(0, 0, mZOffset + mNumber * 2 * mBarLength + mBarLength, nullptr); } else { modTrans = new TGeoCombiTrans(0, 0, mZOffset + mNumber * 2 * sumWidth + sumWidth, nullptr); @@ -184,7 +202,7 @@ void MIDLayer::Stave::Module::Sensor::createSensor(TGeoVolume* motherVolume) { LOGP(debug, "\t\t\t\tCreating MIDSensor: {}", mName); TGeoBBox* sensor = nullptr; - if (!mLayer) { + if (!(mLayer % 2)) { sensor = new TGeoBBox(mName.c_str(), mWidth, mThickness, mLength); } else { sensor = new TGeoBBox(mName.c_str(), mLength, mThickness, mWidth); @@ -194,7 +212,7 @@ void MIDLayer::Stave::Module::Sensor::createSensor(TGeoVolume* motherVolume) sensorVolume->SetVisibility(true); auto totWidth = mWidth + mSpacing / 2; TGeoTranslation* sensorTrans = nullptr; - if (!mLayer) { + if (!(mLayer % 2)) { sensorTrans = new TGeoTranslation(mModuleOffset + 2 * totWidth * mNumber + totWidth, 0, 0); sensorVolume->SetLineColor(kAzure + 4); sensorVolume->SetTransparency(50); diff --git a/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h index 1ce48ea908b4e..7f2244e43a792 100644 --- a/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h +++ b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h @@ -27,12 +27,14 @@ namespace passive enum MagnetLayout : int { AluminiumStabilizer = 0, CopperStabilizer = 1, - WindingPack = 2 + WindingPack = 2, + IanMagnet = 3 }; enum DetLayout : int { StandardRadius = 0, - ReducedRadius = 1 + ReducedRadius = 1, + IanAbsorber = 2 }; struct Alice3PassiveBaseParam : public o2::conf::ConfigurableParamHelper { diff --git a/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx b/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx index 924d977247c89..a0608181a4745 100644 --- a/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx +++ b/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx @@ -130,8 +130,9 @@ void Alice3Absorber::ConstructGeometry() LOG(fatal) << "Could not find the barrel volume while constructing absorber geometry"; } - TGeoPcon* absorings = new TGeoPcon(0., 360., 18); auto& passiveBaseParam = Alice3PassiveBaseParam::Instance(); + int nSections = (passiveBaseParam.mDetLayout == o2::passive::DetLayout::IanAbsorber) ? 6 : 18; + TGeoPcon* absorings = new TGeoPcon(0., 360., nSections); switch (passiveBaseParam.mDetLayout) { case o2::passive::DetLayout::StandardRadius: absorings->DefineSection(0, 500, 236, 274); @@ -173,6 +174,17 @@ void Alice3Absorber::ConstructGeometry() absorings->DefineSection(16, -400, 201, 239); absorings->DefineSection(17, -500, 201, 239); break; + case o2::passive::DetLayout::IanAbsorber: + // 3-section absorber — Ian Perez Garcia (ICN-UNAM), tesis §3.4.7 Geometría 8 + // Rmin=220 cm fijo, grosor variable: 45 cm secciones externas, 70 cm central + // Secciones: z=[-500,-300], [-300,+300], [+300,+500] + absorings->DefineSection(0, 500, 220, 265); // seccion externa: grosor 45 cm + absorings->DefineSection(1, 300, 220, 265); + absorings->DefineSection(2, 300, 220, 290); // seccion central: grosor 70 cm + absorings->DefineSection(3, -300, 220, 290); + absorings->DefineSection(4, -300, 220, 265); // seccion externa: grosor 45 cm + absorings->DefineSection(5, -500, 220, 265); + break; default: LOG(fatal) << "Unknown detector layout " << passiveBaseParam.mDetLayout; break; diff --git a/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx b/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx index f5272ca1d2ccd..265029c285ee5 100644 --- a/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx +++ b/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx @@ -123,6 +123,7 @@ void Alice3Magnet::ConstructGeometry() case o2::passive::DetLayout::StandardRadius: // Defined in the header file break; + case o2::passive::DetLayout::IanAbsorber: // Ian absorber uses ReducedRadius magnet case o2::passive::DetLayout::ReducedRadius: mInnerWrapInnerRadius = 125.f; // cm mInnerWrapThickness = 1.f; // cm @@ -155,6 +156,20 @@ void Alice3Magnet::ConstructGeometry() doWindingPack = true; LOG(debug) << "Alice 3 magnet: using WindingPack (NbTi+Cu+Al) coil"; break; + case o2::passive::MagnetLayout::IanMagnet: + // Ian Perez Garcia design (ICN-UNAM) — radios desde DetectorConstruction.cc + doWindingPack = true; // usa WindingPack como material del coil + mInnerWrapInnerRadius = 140.f; // cm — pared interna criostato + mInnerWrapThickness = 1.0f; // cm — Al + mCoilInnerRadius = 160.f; // cm — bobina (tras gap de vacío) + mCoilThickness = 0.3f; // cm — NbTi/Cu + mRestMaterialRadius = 160.3f;// cm — soporte bobina + mRestMaterialThickness = 15.7f; // cm — Al + mOuterWrapInnerRadius = 197.f; // cm — soporte restante (6 cm Al) + pared externa + mOuterWrapThickness = 3.0f; // cm — pared externa Al, R=197-200 + mZLength = 800.f; // cm + LOG(debug) << "Alice 3 magnet: using Ian Perez Garcia design (ICN-UNAM)"; + break; default: LOG(fatal) << "Unknown magnet layout " << passiveBaseParam.mLayout; break; From 9fe6ea647f256c4f2f26ecadc4336e246dbd5f14 Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Tue, 11 Aug 2026 13:52:19 -0600 Subject: [PATCH 07/13] =?UTF-8?q?ICN-UNAM:=20IanAbsorber=20=E2=80=94=20Geo?= =?UTF-8?q?metria=206=20(Antonio):=20cara=20externa=20plana=20Rmax=3D290,?= =?UTF-8?q?=20escalon=20hacia=20adentro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Upgrades/ALICE3/Passive/src/Absorber.cxx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx b/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx index a0608181a4745..fc749fceb725c 100644 --- a/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx +++ b/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx @@ -175,15 +175,14 @@ void Alice3Absorber::ConstructGeometry() absorings->DefineSection(17, -500, 201, 239); break; case o2::passive::DetLayout::IanAbsorber: - // 3-section absorber — Ian Perez Garcia (ICN-UNAM), tesis §3.4.7 Geometría 8 - // Rmin=220 cm fijo, grosor variable: 45 cm secciones externas, 70 cm central - // Secciones: z=[-500,-300], [-300,+300], [+300,+500] - absorings->DefineSection(0, 500, 220, 265); // seccion externa: grosor 45 cm - absorings->DefineSection(1, 300, 220, 265); - absorings->DefineSection(2, 300, 220, 290); // seccion central: grosor 70 cm - absorings->DefineSection(3, -300, 220, 290); - absorings->DefineSection(4, -300, 220, 265); // seccion externa: grosor 45 cm - absorings->DefineSection(5, -500, 220, 265); + // Geometria 6 (Antonio/tesis): cara externa plana Rmax=290, escalon hacia adentro. + // Externas ~48 cm (Rmin=242), central 70 cm (Rmin=220). ~4 lambda_int en ambas. + absorings->DefineSection(0, -500, 242, 290); + absorings->DefineSection(1, -300, 242, 290); + absorings->DefineSection(2, -300, 220, 290); + absorings->DefineSection(3, 300, 220, 290); + absorings->DefineSection(4, 300, 242, 290); + absorings->DefineSection(5, 500, 242, 290); break; default: LOG(fatal) << "Unknown detector layout " << passiveBaseParam.mDetLayout; From 6c3f33a7ad6d8715cc020d01221832416428cb8c Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Tue, 11 Aug 2026 14:18:11 -0600 Subject: [PATCH 08/13] ICN-UNAM: cleanup diagnostic instrumentation and translate comments to English --- .../ALICE3/MID/simulation/src/Detector.cxx | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx index 8eb7d5fcec1d9..d19dda35a2eb0 100644 --- a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx @@ -93,7 +93,19 @@ void Detector::InitializeO2Detector() { LOG(info) << "Initialize MID O2Detector"; mGeometryTGeo = GeometryTGeo::Instance(); - // defineSensitiveVolumes(); + // Register sensitive volumes + TObjArray* allVols = gGeoManager->GetListOfVolumes(); + TString sensorPattern = GeometryTGeo::getMIDSensorPattern(); + std::set registered; + for (int i = 0; i < allVols->GetEntries(); i++) { + TGeoVolume* v = (TGeoVolume*)allVols->At(i); + TString vname = v->GetName(); + if (vname.Contains(sensorPattern) && registered.find(v) == registered.end()) { + AddSensitiveVolume(v); + registered.insert(v); + } + } + LOGP(info, "Total MI3 sensitive volumes registered: {}", registered.size()); } void Detector::EndOfEvent() { Reset(); } @@ -147,14 +159,13 @@ void Detector::createGeometry() constexpr float kRExt0 = 265.f + kAbsGap; // 276 cm constexpr float kRExt1 = kRExt0 + kPitch; // 286 cm mLayers.resize(6); - // length = semi-longitud = nModulesZ x paso - // capa 0: paso=49.9, capa 1: paso=52 (sumWidth) - mLayers[0] = MIDLayer(0, "MIDLayer0_central", kRCen0, 299.4f, 16, 0.f, 6); // 6 mod x 49.9 - mLayers[1] = MIDLayer(1, "MIDLayer1_central", kRCen1, 312.f, 16, 0.f, 6); // 6 mod x 52 - mLayers[2] = MIDLayer(2, "MIDLayer0_forward", kRExt0, 99.8f, 16, +400.f, 2, -1.f, 21); // 2 mod x 49.9, nBars=21 for R=276 - mLayers[3] = MIDLayer(3, "MIDLayer1_forward", kRExt1, 104.f, 16, +405.f, 2); // 2 mod x 52, +5 offset to clear absorber at z=300 - mLayers[4] = MIDLayer(4, "MIDLayer0_backward", kRExt0, 99.8f, 16, -400.f, 2, -1.f, 21); // 2 mod x 49.9, nBars=21 for R=276 - mLayers[5] = MIDLayer(5, "MIDLayer1_backward", kRExt1, 104.f, 16, -405.f, 2); // 2 mod x 52, -5 offset to clear absorber at z=-300 + // length = semi-length = nModulesZ x step (layer0: step=49.9cm, layer1: step=52cm) + mLayers[0] = MIDLayer(0, "MIDLayer0_central", kRCen0, 299.4f, 16, 0.f, 6); // 6 modules x 49.9 cm step + mLayers[1] = MIDLayer(1, "MIDLayer1_central", kRCen1, 312.f, 16, 0.f, 6); // 6 modules x 52 cm step + mLayers[2] = MIDLayer(2, "MIDLayer0_forward", kRExt0, 99.8f, 16, +400.f, 2, -1.f, 21); // 2 modules x 49.9 cm step, nBars=21 for R=276 cm + mLayers[3] = MIDLayer(3, "MIDLayer1_forward", kRExt1, 104.f, 16, +405.f, 2); // 2 modules x 52 cm step, +5 cm offset to clear absorber transition + mLayers[4] = MIDLayer(4, "MIDLayer0_backward", kRExt0, 99.8f, 16, -400.f, 2, -1.f, 21); // 2 modules x 49.9 cm step, nBars=21 for R=276 cm + mLayers[5] = MIDLayer(5, "MIDLayer1_backward", kRExt1, 104.f, 16, -405.f, 2); // 2 modules x 52 cm step, -5 cm offset to clear absorber transition } else { mLayers.resize(2); mLayers[0] = MIDLayer(0, GeometryTGeo::composeSymNameLayer(0), 266.f, 500.f); @@ -164,21 +175,7 @@ void Detector::createGeometry() for (auto& layer : mLayers) { layer.createLayer(vMID); } - // Register sensitive volumes by iterating all volumes - TObjArray* allVols = gGeoManager->GetListOfVolumes(); - TString sensorPattern = GeometryTGeo::getMIDSensorPattern(); - std::set registered; - for (int i = 0; i < allVols->GetEntries(); i++) { - TGeoVolume* v = (TGeoVolume*)allVols->At(i); - TString vname = v->GetName(); - // Match volumes whose name starts with MIDSensor - if (vname.Contains(sensorPattern) && registered.find(v) == registered.end()) { - AddSensitiveVolume(v); - registered.insert(v); - LOGP(info, "Adding MI3 Sensitive Volume {}", v->GetName()); - } - } - LOGP(info, "Total MI3 sensitive volumes registered: {}", registered.size()); + } void Detector::Reset() From b3174b16abf1b7095f58aa66bd705df6d3096b38 Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Tue, 11 Aug 2026 17:01:57 -0600 Subject: [PATCH 09/13] =?UTF-8?q?ICN-UNAM:=20fix=20hit=20production=20?= =?UTF-8?q?=E2=80=94=20simple=20sensor=20names=20for=20VMC=20resolution=20?= =?UTF-8?q?and=20reset=20mHitStarted=20on=20Reset()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx | 1 + Detectors/Upgrades/ALICE3/MID/simulation/src/MIDLayer.cxx | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx index d19dda35a2eb0..0b19e9c0519ea 100644 --- a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx @@ -183,6 +183,7 @@ void Detector::Reset() if (!o2::utils::ShmManager::Instance().isOperational()) { mHits->clear(); } + mTrackData.mHitStarted = false; } bool Detector::ProcessHits(FairVolume* vol) diff --git a/Detectors/Upgrades/ALICE3/MID/simulation/src/MIDLayer.cxx b/Detectors/Upgrades/ALICE3/MID/simulation/src/MIDLayer.cxx index 2b42619ad4ecd..133b172b68740 100644 --- a/Detectors/Upgrades/ALICE3/MID/simulation/src/MIDLayer.cxx +++ b/Detectors/Upgrades/ALICE3/MID/simulation/src/MIDLayer.cxx @@ -208,7 +208,9 @@ void MIDLayer::Stave::Module::Sensor::createSensor(TGeoVolume* motherVolume) sensor = new TGeoBBox(mName.c_str(), mLength, mThickness, mWidth); } auto* polyMed = gGeoManager->GetMedium("MI3_POLYSTYRENE"); - TGeoVolume* sensorVolume = new TGeoVolume(mName.c_str(), sensor, polyMed); + // Simple unique name without slashes so gMC->VolId() resolves correctly during stepping + auto volName = Form("MIDSensor_L%d_S%d_M%d_B%d", mLayer, mStave, mNumber, mNumber); + TGeoVolume* sensorVolume = new TGeoVolume(volName, sensor, polyMed); sensorVolume->SetVisibility(true); auto totWidth = mWidth + mSpacing / 2; TGeoTranslation* sensorTrans = nullptr; From a03c7f0179c3cc51c002b54c69ba1ee42e4e8394 Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Thu, 13 Aug 2026 03:03:23 -0600 Subject: [PATCH 10/13] =?UTF-8?q?ICN-UNAM:=20fix=20physLay=20in=20ProcessH?= =?UTF-8?q?its=20=E2=80=94=20extract=20layer=20index=20from=20sensor=20nam?= =?UTF-8?q?e;=20remove=20ITS=20TrackReference=20boilerplate;=20guard=20aga?= =?UTF-8?q?inst=20invalid=20physLay?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ALICE3/MID/simulation/src/Detector.cxx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx index 0b19e9c0519ea..6fdbd6f32b5a1 100644 --- a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx @@ -106,6 +106,7 @@ void Detector::InitializeO2Detector() } } LOGP(info, "Total MI3 sensitive volumes registered: {}", registered.size()); + } void Detector::EndOfEvent() { Reset(); } @@ -196,14 +197,15 @@ bool Detector::ProcessHits(FairVolume* vol) int lay = vol->getVolumeId(); int volID = vol->getMCid(); - // Is it needed to keep a track reference when the outer ITS volume is encountered? + // TrackReference block removed: ITS boilerplate whose condition (lay == 0 + // against a TGeo volume ID) never fired. No MID reconstruction consumes + // MID track references at present. auto stack = (o2::data::Stack*)fMC->GetStack(); - if (fMC->IsTrackExiting() && (lay == 0)) { - o2::TrackReference tr(*fMC, GetDetId()); - tr.setTrackID(stack->GetCurrentTrackNumber()); - tr.setUserId(lay); - stack->addTrackReference(tr); - } + // Extract physical layer index (0 or 1) from sensor name: MIDSensor_L_S... + int physLay = -1; + const char* volName = fMC->CurrentVolName(); + sscanf(volName, "MIDSensor_L%d", &physLay); + if (physLay >= 0) physLay = physLay % 2; bool startHit = false, stopHit = false; unsigned char status = 0; if (fMC->IsTrackEntering()) { @@ -257,7 +259,8 @@ bool Detector::ProcessHits(FairVolume* vol) fMC->CurrentVolOffID(3, halfstave); fMC->CurrentVolOffID(4, stave); - Hit* p = addHit(stack->GetCurrentTrackNumber(), lay, mTrackData.mPositionStart.Vect(), positionStop.Vect(), + if (physLay < 0) { return false; } // guard: sensor name did not match expected pattern + Hit* p = addHit(stack->GetCurrentTrackNumber(), physLay, mTrackData.mPositionStart.Vect(), positionStop.Vect(), mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(), mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status); // p->SetTotalEnergy(vmc->Etot()); From 54a5df34503735002b9b2e58332894de18157430 Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Thu, 13 Aug 2026 04:37:32 -0600 Subject: [PATCH 11/13] ICN-UNAM: document CurrentVolOffID limitation; full sensor location available via sensor name pattern --- .../Upgrades/ALICE3/MID/simulation/src/Detector.cxx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx index 6fdbd6f32b5a1..9dc0c296be8e0 100644 --- a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx @@ -252,12 +252,11 @@ bool Detector::ProcessHits(FairVolume* vol) if (stopHit) { TLorentzVector positionStop; fMC->TrackPosition(positionStop); - // Retrieve the indices with the volume path - int stave(0), halfstave(0), chipinmodule(0), module; - fMC->CurrentVolOffID(1, chipinmodule); - fMC->CurrentVolOffID(2, module); - fMC->CurrentVolOffID(3, halfstave); - fMC->CurrentVolOffID(4, stave); + // CurrentVolOffID(1..4) yields copy numbers of module/halfstave/stave ancestors. + // With TGeoVolumeAssembly nodes these are always 0 except the stave level. + // Full sensor location (layer, stave, module, bar) is encoded in the sensor + // name (MIDSensor_L_S_M_B) and can be decoded with sscanf if needed. + // Left as future work for hit digitization. if (physLay < 0) { return false; } // guard: sensor name did not match expected pattern Hit* p = addHit(stack->GetCurrentTrackNumber(), physLay, mTrackData.mPositionStart.Vect(), positionStop.Vect(), From 84b53c586da2a162599d7fc55253a67fa2b8242d Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Thu, 13 Aug 2026 04:56:07 -0600 Subject: [PATCH 12/13] =?UTF-8?q?ICN-UNAM:=20IanAbsorber=20=E2=80=94=20cor?= =?UTF-8?q?rect=20external=20Rmin=20to=20245=20cm=20(45=20cm=20thickness?= =?UTF-8?q?=20per=20Ian=20reference=20code)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx b/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx index fc749fceb725c..10ef12e090817 100644 --- a/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx +++ b/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx @@ -176,13 +176,14 @@ void Alice3Absorber::ConstructGeometry() break; case o2::passive::DetLayout::IanAbsorber: // Geometria 6 (Antonio/tesis): cara externa plana Rmax=290, escalon hacia adentro. - // Externas ~48 cm (Rmin=242), central 70 cm (Rmin=220). ~4 lambda_int en ambas. - absorings->DefineSection(0, -500, 242, 290); - absorings->DefineSection(1, -300, 242, 290); + // Externas 45 cm (Rmin=245), central 70 cm (Rmin=220). ~4 lambda_int en ambas. + // Ref: Ian Perez Garcia DetectorConstruction.cc abs_thickness = {45., 70., 45.} + absorings->DefineSection(0, -500, 245, 290); + absorings->DefineSection(1, -300, 245, 290); absorings->DefineSection(2, -300, 220, 290); absorings->DefineSection(3, 300, 220, 290); - absorings->DefineSection(4, 300, 242, 290); - absorings->DefineSection(5, 500, 242, 290); + absorings->DefineSection(4, 300, 245, 290); + absorings->DefineSection(5, 500, 245, 290); break; default: LOG(fatal) << "Unknown detector layout " << passiveBaseParam.mDetLayout; From 6e1f4f403e246b9265b81c8150a6d6f797a17c40 Mon Sep 17 00:00:00 2001 From: Jose Francisco Esquivel Nestor Date: Thu, 13 Aug 2026 05:08:38 -0600 Subject: [PATCH 13/13] =?UTF-8?q?ICN-UNAM:=20rename=20enum=20values=20?= =?UTF-8?q?=E2=80=94=20IanMagnet->SuperconductingMagnet,=20IanAbsorber->St?= =?UTF-8?q?eppedAbsorber,=20ICNStepped->SteppedLayout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Upgrades/ALICE3/MID/base/include/MI3Base/MI3BaseParam.h | 2 +- Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx | 2 +- .../Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h | 4 ++-- Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx | 4 ++-- Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/MID/base/include/MI3Base/MI3BaseParam.h b/Detectors/Upgrades/ALICE3/MID/base/include/MI3Base/MI3BaseParam.h index 18ba531d40ae3..2106329714738 100644 --- a/Detectors/Upgrades/ALICE3/MID/base/include/MI3Base/MI3BaseParam.h +++ b/Detectors/Upgrades/ALICE3/MID/base/include/MI3Base/MI3BaseParam.h @@ -27,7 +27,7 @@ namespace mi3 enum MIDLayout : int { StandardRadius = 0, ReducedRadius = 1, - ICNStepped = 2 + SteppedLayout = 2 }; struct MIDBaseParam : public o2::conf::ConfigurableParamHelper { diff --git a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx index 9dc0c296be8e0..f167a24d4744b 100644 --- a/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/MID/simulation/src/Detector.cxx @@ -146,7 +146,7 @@ void Detector::createGeometry() mLayers.resize(2); mLayers[0] = MIDLayer(0, GeometryTGeo::composeSymNameLayer(0), 301.f, 500.f); mLayers[1] = MIDLayer(1, GeometryTGeo::composeSymNameLayer(1), 311.f, 520.f); // arbitrarily reduced to get multiple of 5.2f - } else if (midParam.mLayout == o2::mi3::MIDLayout::ICNStepped) { + } else if (midParam.mLayout == o2::mi3::MIDLayout::SteppedLayout) { // Ian Perez Garcia design (ICN-UNAM) — tesis §3.4.7 Geometria 8 // 11 cm gap from absorber outer face to MID layer // mLayer index is flat 0-5: even = physical layer 0, odd = physical layer 1 diff --git a/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h index 7f2244e43a792..82f3a2b5a4b16 100644 --- a/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h +++ b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/PassiveBaseParam.h @@ -28,13 +28,13 @@ enum MagnetLayout : int { AluminiumStabilizer = 0, CopperStabilizer = 1, WindingPack = 2, - IanMagnet = 3 + SuperconductingMagnet = 3 }; enum DetLayout : int { StandardRadius = 0, ReducedRadius = 1, - IanAbsorber = 2 + SteppedAbsorber = 2 }; struct Alice3PassiveBaseParam : public o2::conf::ConfigurableParamHelper { diff --git a/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx b/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx index 10ef12e090817..4d0b9c42be4d2 100644 --- a/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx +++ b/Detectors/Upgrades/ALICE3/Passive/src/Absorber.cxx @@ -131,7 +131,7 @@ void Alice3Absorber::ConstructGeometry() } auto& passiveBaseParam = Alice3PassiveBaseParam::Instance(); - int nSections = (passiveBaseParam.mDetLayout == o2::passive::DetLayout::IanAbsorber) ? 6 : 18; + int nSections = (passiveBaseParam.mDetLayout == o2::passive::DetLayout::SteppedAbsorber) ? 6 : 18; TGeoPcon* absorings = new TGeoPcon(0., 360., nSections); switch (passiveBaseParam.mDetLayout) { case o2::passive::DetLayout::StandardRadius: @@ -174,7 +174,7 @@ void Alice3Absorber::ConstructGeometry() absorings->DefineSection(16, -400, 201, 239); absorings->DefineSection(17, -500, 201, 239); break; - case o2::passive::DetLayout::IanAbsorber: + case o2::passive::DetLayout::SteppedAbsorber: // Geometria 6 (Antonio/tesis): cara externa plana Rmax=290, escalon hacia adentro. // Externas 45 cm (Rmin=245), central 70 cm (Rmin=220). ~4 lambda_int en ambas. // Ref: Ian Perez Garcia DetectorConstruction.cc abs_thickness = {45., 70., 45.} diff --git a/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx b/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx index 265029c285ee5..2a5a985cbd3da 100644 --- a/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx +++ b/Detectors/Upgrades/ALICE3/Passive/src/Magnet.cxx @@ -123,7 +123,7 @@ void Alice3Magnet::ConstructGeometry() case o2::passive::DetLayout::StandardRadius: // Defined in the header file break; - case o2::passive::DetLayout::IanAbsorber: // Ian absorber uses ReducedRadius magnet + case o2::passive::DetLayout::SteppedAbsorber: // Ian absorber uses ReducedRadius magnet case o2::passive::DetLayout::ReducedRadius: mInnerWrapInnerRadius = 125.f; // cm mInnerWrapThickness = 1.f; // cm @@ -156,7 +156,7 @@ void Alice3Magnet::ConstructGeometry() doWindingPack = true; LOG(debug) << "Alice 3 magnet: using WindingPack (NbTi+Cu+Al) coil"; break; - case o2::passive::MagnetLayout::IanMagnet: + case o2::passive::MagnetLayout::SuperconductingMagnet: // Ian Perez Garcia design (ICN-UNAM) — radios desde DetectorConstruction.cc doWindingPack = true; // usa WindingPack como material del coil mInnerWrapInnerRadius = 140.f; // cm — pared interna criostato