diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h index d5e11313c0f0c..79588c1130c2b 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h @@ -34,6 +34,7 @@ enum eLayout { enum eVDLayout { kIRIS4 = 0, kIRISFullCyl, + kIRISFullCyl3InclinedWalls, kIRIS5, kIRIS4a, }; diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/VDGeometryBuilder.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/VDGeometryBuilder.h index c337ddb102147..77b45c97cba84 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/VDGeometryBuilder.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/VDGeometryBuilder.h @@ -25,6 +25,7 @@ namespace o2::trk // and then places/rotates the petal once into the mother volume. void createIRISGeometryFullCyl(TGeoVolume* motherVolume); // Full-cylinder IRIS geometry (no petals, no gaps, no side walls) +void createIRISGeometry3InclinedWalls(TGeoVolume* motherVolume); // Full-cylinder IRIS geometry with 3 inclined walls void createIRISGeometryFullCylwithDisks(TGeoVolume* motherVolume); // Full-cylinder IRIS geometry (no petals, no gaps, no side walls) incl. disks void createIRIS4Geometry(TGeoVolume* motherVolume); // 4 petals, cylindrical L0 void createIRIS4aGeometry(TGeoVolume* motherVolume); // 3 petals, cylindrical L0 diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx index 556b016f22553..035ad02a68876 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx @@ -275,6 +275,10 @@ void Detector::createGeometry() LOG(info) << "Building VD with IRIS fully cylindrical layout"; o2::trk::createIRISGeometryFullCyl(vTRK); break; + case kIRISFullCyl3InclinedWalls: + LOG(info) << "Building VD with IRIS fully cylindrical layout with 3 inclined walls"; + o2::trk::createIRISGeometry3InclinedWalls(vTRK); + break; case kIRIS5: LOG(info) << "Building VD with IRIS5 layout"; o2::trk::createIRIS5Geometry(vTRK); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx index b06faa38211bb..643a6bdd94808 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx @@ -10,7 +10,6 @@ // or submit itself to any jurisdiction. #include "TRKSimulation/VDGeometryBuilder.h" - #include #include #include @@ -19,13 +18,13 @@ #include #include #include - #include "TGeoManager.h" - #include "Framework/Logger.h" #include "TRKBase/GeometryTGeo.h" #include "TRKSimulation/VDLayer.h" #include "TRKSimulation/VDSensorRegistry.h" +#include +#include namespace o2::trk { @@ -82,6 +81,9 @@ inline bool isSolidToCut(const TGeoVolume* v) if (TString(nm).BeginsWith("IRIS_Service_Pos_InVac")) { return true; } + if (TString(nm).BeginsWith("VD_InclinedWall")) { + return true; + } return false; } @@ -253,7 +255,17 @@ static constexpr double kPetalZ_cm = 70.0f; // full wall height static constexpr double kWallThick_cm = 0.015f; // 0.15 mm static constexpr double kInnerWallRadius_cm = 0.48f; // 4.8 mm (ALWAYS cylindrical) static constexpr double kOuterWallRadius_cm = 3.0f; // 30 mm (can be changed) -static constexpr double kEps_cm = 1.e-4f; +static constexpr double kEps_cm = 2.5e-4f; + +// 3 inclined walls ("walls") specs for the full-cylinder option +// Thickness in-plane (cm). This is the short half-dimension of the TGeoBBox in XY. +static constexpr double kInclinedWallThick_cm = 0.04f; // 0.4 mm +// Layer-shell thickness used for the gap boundaries in the inclined-wall construction (cm) +static constexpr double kSiLayerThick_cm = 0.01f; // 0.1 mm +// Base tangency angle (deg) for the first wall; the other 2 are +120/+240. +// This matches the angle used in the ROOT sketch from our chat. +static constexpr double kInclinedWallPhi0_deg = 27.799f; +static constexpr double kInclinedWallRmax_cm = 4.75f; // 47.5 mm outer extension // Coldplate specs (cm) static constexpr double kColdplateRadius_cm = 2.6f; // 26 mm (outer radius) @@ -806,6 +818,158 @@ static TGeoVolume* buildFullCylAssembly(int petalID, bool withDisks) return petalAsm; } +// Add 3 inclined walls (straight walls) into a full-cylinder petal assembly. +// The walls are implemented as TWO TGeoBBox segments per wall, living in the gaps: +// - segment 01: from tangency at Rtan to inner surface of L1 +// - segment 12: from outer surface of L1 to inner surface of L2 +// The construction accounts for the finite wall thickness (kInclinedWallThick_cm). +static void addInclinedWalls3FullCyl(TGeoVolume* petalAsm, double phi0_deg = kInclinedWallPhi0_deg) +{ + if (!petalAsm) { + LOGP(error, "addInclinedWalls3FullCyl: petalAsm is null"); + return; + } + + auto& matmgr = o2::base::MaterialManager::Instance(); + const TGeoMedium* med = matmgr.getTGeoMedium("ALICE3_TRKSERVICES_ALUMINIUM5083"); + if (!med) { + LOGP(warning, "addInclinedWalls3FullCyl: ALICE3_TRKSERVICES_ALUMINIUM5083 not found, walls not created."); + return; + } + + // Clearance margin from layer/coldplate surfaces (cm) + constexpr double clearanceMargin = 0.010; // 100 microns + + // Geometry inputs (cm) + constexpr double R0 = rL0_cm; + constexpr double R1 = rL1_cm; + constexpr double R2 = rL2_cm; + constexpr double Rmax = kInclinedWallRmax_cm; + + const double wallDy = 0.5 * kInclinedWallThick_cm; + const double shellTh = kSiLayerThick_cm; // 0.1 mm shell thickness for bounds + const double h = 0.5 * shellTh; + const double dz = 0.5 * kLenZ_cm; // match barrel/coldplate length in full-cyl option + + constexpr int nWalls = 3; + constexpr double dPhi = 360.0 / double(nWalls); + + // Gap boundaries (shell surfaces) + const double R0_out = R0 + h; + const double R1_in = R1 - h; + const double R1_out = R1 + h; + const double R2_in = R2 - h; + const double R2_out = R2 + h; + + // Coldplate outer radius (tube segment is [kColdplateRadius_cm, kColdplateRadius_cm + kColdplateThickness_cm]) + const double Rcold_out = kColdplateRadius_cm + kColdplateThickness_cm; + + // Tangency radius choice (thickness-safe at s=0): need Rtan - wallDy >= R0_out + const double Rtan = R0_out + wallDy + clearanceMargin; + + // For finite-thickness box: + // outermost edge uses Reff_plus, innermost edge uses Reff_minus + const double Reff_plus = Rtan + wallDy + clearanceMargin; + const double Reff_minus = std::max(0.0, Rtan - wallDy - clearanceMargin); + + auto sAt = [](double R, double Reff) -> double { + const double v = R * R - Reff * Reff; + return (v > 0.0) ? std::sqrt(v) : 0.0; + }; + + // Segment bounds in 's' (thickness-safe): + // 01: from tangency to L1 inner surface (outer edge <= R1_in) + const double sa01 = 0.0; + const double sb01 = sAt(R1_in, Reff_plus); + + // 12: from outside L1 to inside L2 + const double sa12 = sAt(R1_out, Reff_minus); // inner edge >= R1_out + const double sb12 = sAt(R2_in, Reff_plus); // outer edge <= R2_in + + // 23: from outside coldplate (and outside L2) to Rmax + const double R23_start = std::max(R2_out, Rcold_out) + clearanceMargin; + const double sa23 = sAt(R23_start, Reff_minus); // inner edge >= start radius + const double sb23 = sAt(Rmax, Reff_plus); // outer edge <= Rmax + + if (!((sb01 > sa01) && (sb12 > sa12) && (sb23 > sa23))) { + LOGP(error, + "addInclinedWalls3FullCyl: invalid bounds. 01:[{},{}] 12:[{},{}] 23:[{},{}] " + "Rtan={} Reff-={} Reff+={} R23_start={}", + sa01, sb01, sa12, sb12, sa23, sb23, + Rtan, Reff_minus, Reff_plus, R23_start); + return; + } + + // Half-lengths and center parameters (s-centers) + const double dx01 = 0.5 * (sb01 - sa01); + const double dx12 = 0.5 * (sb12 - sa12); + const double dx23 = 0.5 * (sb23 - sa23); + + const double sc01 = 0.5 * (sa01 + sb01); + const double sc12 = 0.5 * (sa12 + sb12); + const double sc23 = 0.5 * (sa23 + sb23); + + // Create shapes once, reuse for all walls + auto* sh01 = new TGeoBBox(dx01, wallDy, dz); + auto* sh12 = new TGeoBBox(dx12, wallDy, dz); + auto* sh23 = new TGeoBBox(dx23, wallDy, dz); + sh01->SetName("VD_InclinedWall01_sh"); + sh12->SetName("VD_InclinedWall12_sh"); + sh23->SetName("VD_InclinedWall23_sh"); + + const double phi0_rad = phi0_deg * TMath::DegToRad(); + + for (int i = 0; i < nWalls; ++i) { + const double phi = phi0_rad + i * (dPhi * TMath::DegToRad()); + const double cosPhi = std::cos(phi); + const double sinPhi = std::sin(phi); + + // Tangency point on Rtan + const double xT = Rtan * cosPhi; + const double yT = Rtan * sinPhi; + + // Tangent direction u = (-sin, cos) + const double ux = -sinPhi; + const double uy = cosPhi; + + // Centers (in XY) + const double cx01 = xT + sc01 * ux; + const double cy01 = yT + sc01 * uy; + const double cx12 = xT + sc12 * ux; + const double cy12 = yT + sc12 * uy; + const double cx23 = xT + sc23 * ux; + const double cy23 = yT + sc23 * uy; + + // Rotation: local X along tangent => angle = phi + 90° + const double alpha_deg = phi0_deg + i * dPhi + 90.0; + auto* rot = new TGeoRotation(); + rot->RotateZ(alpha_deg); + + // Create volumes per wall (unique names) + auto* v01 = new TGeoVolume(Form("VD_InclinedWall01_%d", i), sh01, med); + auto* v12 = new TGeoVolume(Form("VD_InclinedWall12_%d", i), sh12, med); + auto* v23 = new TGeoVolume(Form("VD_InclinedWall23_%d", i), sh23, med); + v01->SetLineColor(kOrange + 7); + v12->SetLineColor(kOrange + 7); + v23->SetLineColor(kOrange + 7); + v01->SetTransparency(70); + v12->SetTransparency(70); + v23->SetTransparency(70); + + auto* T01 = new TGeoCombiTrans(cx01, cy01, 0.0, rot); + auto* T12 = new TGeoCombiTrans(cx12, cy12, 0.0, new TGeoRotation(*rot)); + auto* T23 = new TGeoCombiTrans(cx23, cy23, 0.0, new TGeoRotation(*rot)); + + petalAsm->AddNode(v01, 1, T01); + petalAsm->AddNode(v12, 1, T12); + petalAsm->AddNode(v23, 1, T23); + + LOGP(debug, + "InclinedWall {}: 01({:.3f},{:.3f}) 12({:.3f},{:.3f}) 23({:.3f},{:.3f}) angle={:.2f}°", + i, cx01, cy01, cx12, cy12, cx23, cy23, alpha_deg); + } +} + // =================== Public entry points =================== void createIRIS4Geometry(TGeoVolume* motherVolume) @@ -908,6 +1072,31 @@ void createIRISGeometryFullCyl(TGeoVolume* motherVolume) buildIrisCutoutFromPetalSolid(nPetals); } +void createIRISGeometry3InclinedWalls(TGeoVolume* motherVolume) +{ + if (!motherVolume) { + LOGP(error, "createIRISGeometry3InclinedWalls: motherVolume is null"); + return; + } + + clearVDSensorRegistry(); + + constexpr int nPetals = 1; + constexpr int petalID = 0; + + // Start from the same content as createIRISGeometryFullCyl + auto* petal = buildFullCylAssembly(petalID, /*withDisks=*/false); + + // Add the 3 inclined walls into the same assembly + addInclinedWalls3FullCyl(petal, kInclinedWallPhi0_deg); + + motherVolume->AddNode(petal, 1, nullptr); + + // Same cutout pipeline as full-cyl + buildPetalSolidsComposite(petal); + buildIrisCutoutFromPetalSolid(nPetals); +} + void createIRISGeometryFullCylwithDisks(TGeoVolume* motherVolume) { if (!motherVolume) {