|
10 | 10 | // or submit itself to any jurisdiction. |
11 | 11 |
|
12 | 12 | #include "TRKSimulation/VDGeometryBuilder.h" |
13 | | - |
14 | 13 | #include <TGeoVolume.h> |
15 | 14 | #include <TGeoMatrix.h> |
16 | 15 | #include <TGeoTube.h> |
|
19 | 18 | #include <TGeoCompositeShape.h> |
20 | 19 | #include <TString.h> |
21 | 20 | #include <DetectorsBase/MaterialManager.h> |
22 | | - |
23 | 21 | #include "TGeoManager.h" |
24 | | - |
25 | 22 | #include "Framework/Logger.h" |
26 | 23 | #include "TRKBase/GeometryTGeo.h" |
27 | 24 | #include "TRKSimulation/VDLayer.h" |
28 | 25 | #include "TRKSimulation/VDSensorRegistry.h" |
| 26 | +#include <algorithm> |
| 27 | +#include <cmath> |
29 | 28 |
|
30 | 29 | namespace o2::trk |
31 | 30 | { |
@@ -82,6 +81,9 @@ inline bool isSolidToCut(const TGeoVolume* v) |
82 | 81 | if (TString(nm).BeginsWith("IRIS_Service_Pos_InVac")) { |
83 | 82 | return true; |
84 | 83 | } |
| 84 | + if (TString(nm).BeginsWith("VD_InclinedWall")) { |
| 85 | + return true; |
| 86 | + } |
85 | 87 | return false; |
86 | 88 | } |
87 | 89 |
|
@@ -253,7 +255,16 @@ static constexpr double kPetalZ_cm = 70.0f; // full wall height |
253 | 255 | static constexpr double kWallThick_cm = 0.015f; // 0.15 mm |
254 | 256 | static constexpr double kInnerWallRadius_cm = 0.48f; // 4.8 mm (ALWAYS cylindrical) |
255 | 257 | static constexpr double kOuterWallRadius_cm = 3.0f; // 30 mm (can be changed) |
256 | | -static constexpr double kEps_cm = 1.e-4f; |
| 258 | +static constexpr double kEps_cm = 2.5e-4f; |
| 259 | + |
| 260 | +// 3 inclined walls ("walls") specs for the full-cylinder option |
| 261 | +// Thickness in-plane (cm). This is the short half-dimension of the TGeoBBox in XY. |
| 262 | +static constexpr double kInclinedWallThick_cm = 0.04f; // 0.4 mm |
| 263 | +// Layer-shell thickness used for the gap boundaries in the inclined-wall construction (cm) |
| 264 | +static constexpr double kSiLayerThick_cm = 0.01f; // 0.1 mm |
| 265 | +// Base tangency angle (deg) for the first wall; the other 2 are +120/+240. |
| 266 | +// This matches the angle used in the ROOT sketch from our chat. |
| 267 | +static constexpr double kInclinedWallPhi0_deg = 27.799f; |
257 | 268 |
|
258 | 269 | // Coldplate specs (cm) |
259 | 270 | static constexpr double kColdplateRadius_cm = 2.6f; // 26 mm (outer radius) |
@@ -806,6 +817,130 @@ static TGeoVolume* buildFullCylAssembly(int petalID, bool withDisks) |
806 | 817 | return petalAsm; |
807 | 818 | } |
808 | 819 |
|
| 820 | +// Add 3 inclined walls (straight walls) into a full-cylinder petal assembly. |
| 821 | +// The walls are implemented as TWO TGeoBBox segments per wall, living in the gaps: |
| 822 | +// - segment 01: from tangency at Rtan to inner surface of L1 |
| 823 | +// - segment 12: from outer surface of L1 to inner surface of L2 |
| 824 | +// The construction accounts for the finite wall thickness (kInclinedWallThick_cm). |
| 825 | +static void addInclinedWalls3FullCyl(TGeoVolume* petalAsm, double phi0_deg = kInclinedWallPhi0_deg) |
| 826 | +{ |
| 827 | + if (!petalAsm) { |
| 828 | + LOGP(error, "addInclinedWalls3FullCyl: petalAsm is null"); |
| 829 | + return; |
| 830 | + } |
| 831 | + |
| 832 | + auto& matmgr = o2::base::MaterialManager::Instance(); |
| 833 | + const TGeoMedium* med = matmgr.getTGeoMedium("ALICE3_TRKSERVICES_ALUMINIUM5083"); |
| 834 | + if (!med) { |
| 835 | + LOGP(warning, "addInclinedWalls3FullCyl: ALICE3_TRKSERVICES_ALUMINIUM5083 not found, walls not created."); |
| 836 | + return; |
| 837 | + } |
| 838 | + // Geometry constants |
| 839 | + constexpr double clearanceMargin = 0.010; // 100 microns from layer surfaces |
| 840 | + |
| 841 | + // Geometry inputs (cm) |
| 842 | + constexpr double R0 = rL0_cm; |
| 843 | + constexpr double R1 = rL1_cm; |
| 844 | + constexpr double R2 = rL2_cm; |
| 845 | + constexpr double wallDy = 0.5 * kInclinedWallThick_cm; |
| 846 | + constexpr double shellTh = kSiLayerThick_cm; |
| 847 | + constexpr double h = 0.5 * shellTh; |
| 848 | + constexpr double dz = 0.5 * kPetalZ_cm; |
| 849 | + constexpr int nWalls = 3; |
| 850 | + constexpr double dPhi = 360.0 / double(nWalls); |
| 851 | + constexpr double eps = kEps_cm; |
| 852 | + |
| 853 | + // Gap boundaries (shell surfaces) |
| 854 | + const double R0_out = R0 + h; |
| 855 | + const double R1_in = R1 - h; |
| 856 | + const double R1_out = R1 + h; |
| 857 | + const double R2_in = R2 - h; |
| 858 | + |
| 859 | + |
| 860 | + // Tangency radius choice |
| 861 | + const double Rtan = R0_out + wallDy + clearanceMargin; |
| 862 | + const double Reff_plus = Rtan + wallDy + clearanceMargin; |
| 863 | + const double Reff_minus = std::max(0.0, Rtan - wallDy - clearanceMargin); |
| 864 | + |
| 865 | + // Lambda for clamped square root |
| 866 | + auto sAt = [](double R, double Reff) -> double { |
| 867 | + const double v = R * R - Reff * Reff; |
| 868 | + return (v > 0.0) ? std::sqrt(v) : 0.0; |
| 869 | + }; |
| 870 | + |
| 871 | + // Segment bounds (computed once outside loop) |
| 872 | + const double sa01 = 0.0; |
| 873 | + const double sb01 = sAt(R1_in, Reff_plus); |
| 874 | + const double sa12 = sAt(R1_out, Reff_minus); |
| 875 | + const double sb12 = sAt(R2_in, Reff_plus); |
| 876 | + |
| 877 | + if (!(sb01 > sa01) || !(sb12 > sa12)) { |
| 878 | + LOGP(error, "addInclinedWalls3FullCyl: invalid bounds. sa01={} sb01={} sa12={} sb12={}", |
| 879 | + sa01, sb01, sa12, sb12); |
| 880 | + return; |
| 881 | + } |
| 882 | + |
| 883 | + // Half-lengths and centers (computed once) |
| 884 | + const double dx01 = 0.5 * (sb01 - sa01); |
| 885 | + const double dx12 = 0.5 * (sb12 - sa12); |
| 886 | + const double sc01 = 0.5 * (sa01 + sb01); |
| 887 | + const double sc12 = 0.5 * (sa12 + sb12); |
| 888 | + |
| 889 | + // Create shapes once, reuse for all walls |
| 890 | + auto* sh01 = new TGeoBBox(dx01, wallDy, dz); |
| 891 | + auto* sh12 = new TGeoBBox(dx12, wallDy, dz); |
| 892 | + sh01->SetName("VD_InclinedWall01_sh"); |
| 893 | + sh12->SetName("VD_InclinedWall12_sh"); |
| 894 | + |
| 895 | + // Convert initial angle to radians once |
| 896 | + const double phi0_rad = phi0_deg * TMath::DegToRad(); |
| 897 | + |
| 898 | + for (int i = 0; i < nWalls; ++i) { |
| 899 | + // Compute angle for this wall |
| 900 | + const double phi = phi0_rad + i * (dPhi * TMath::DegToRad()); |
| 901 | + const double cosPhi = std::cos(phi); |
| 902 | + const double sinPhi = std::sin(phi); |
| 903 | + |
| 904 | + // Tangency point on Rtan |
| 905 | + const double xT = Rtan * cosPhi; |
| 906 | + const double yT = Rtan * sinPhi; |
| 907 | + |
| 908 | + // Tangent direction (perpendicular to radius): (-sin, cos) |
| 909 | + const double ux = -sinPhi; |
| 910 | + const double uy = cosPhi; |
| 911 | + |
| 912 | + // Centers for both segments |
| 913 | + const double cx01 = xT + sc01 * ux; |
| 914 | + const double cy01 = yT + sc01 * uy; |
| 915 | + const double cx12 = xT + sc12 * ux; |
| 916 | + const double cy12 = yT + sc12 * uy; |
| 917 | + |
| 918 | + // Rotation: tangent is perpendicular to radius, so angle = phi + 90° |
| 919 | + const double alpha_deg = phi0_deg + i * dPhi + 90.0; |
| 920 | + auto* rot = new TGeoRotation(); |
| 921 | + rot->RotateZ(alpha_deg); |
| 922 | + |
| 923 | + // Create separate volumes for each wall |
| 924 | + auto* v01 = new TGeoVolume(Form("VD_InclinedWall01_%d", i), sh01, med); |
| 925 | + auto* v12 = new TGeoVolume(Form("VD_InclinedWall12_%d", i), sh12, med); |
| 926 | + v01->SetLineColor(kOrange + 7); |
| 927 | + v12->SetLineColor(kOrange + 7); |
| 928 | + v01->SetTransparency(70); |
| 929 | + v12->SetTransparency(70); |
| 930 | + |
| 931 | + auto* T01 = new TGeoCombiTrans(cx01, cy01, 0.0, rot); |
| 932 | + auto* T12 = new TGeoCombiTrans(cx12, cy12, 0.0, new TGeoRotation(*rot)); // Copy rotation |
| 933 | + |
| 934 | + petalAsm->AddNode(v01, 1, T01); |
| 935 | + petalAsm->AddNode(v12, 1, T12); |
| 936 | + |
| 937 | + LOGP(debug, "Wall {}: 01 at ({:.3f}, {:.3f}), 12 at ({:.3f}, {:.3f}), angle={:.2f}°", |
| 938 | + i, cx01, cy01, cx12, cy12, alpha_deg); |
| 939 | + } |
| 940 | + |
| 941 | + LOGP(info, "Added 3 inclined walls: Rtan={:.3f} cm, thickness={:.3f} cm", Rtan, kInclinedWallThick_cm); |
| 942 | +} |
| 943 | + |
809 | 944 | // =================== Public entry points =================== |
810 | 945 |
|
811 | 946 | void createIRIS4Geometry(TGeoVolume* motherVolume) |
@@ -908,6 +1043,31 @@ void createIRISGeometryFullCyl(TGeoVolume* motherVolume) |
908 | 1043 | buildIrisCutoutFromPetalSolid(nPetals); |
909 | 1044 | } |
910 | 1045 |
|
| 1046 | +void createIRISGeometry3InclinedWalls(TGeoVolume* motherVolume) |
| 1047 | +{ |
| 1048 | + if (!motherVolume) { |
| 1049 | + LOGP(error, "createIRISGeometry3InclinedWalls: motherVolume is null"); |
| 1050 | + return; |
| 1051 | + } |
| 1052 | + |
| 1053 | + clearVDSensorRegistry(); |
| 1054 | + |
| 1055 | + constexpr int nPetals = 1; |
| 1056 | + constexpr int petalID = 0; |
| 1057 | + |
| 1058 | + // Start from the same content as createIRISGeometryFullCyl |
| 1059 | + auto* petal = buildFullCylAssembly(petalID, /*withDisks=*/false); |
| 1060 | + |
| 1061 | + // Add the 3 inclined walls into the same assembly |
| 1062 | + addInclinedWalls3FullCyl(petal, kInclinedWallPhi0_deg); |
| 1063 | + |
| 1064 | + motherVolume->AddNode(petal, 1, nullptr); |
| 1065 | + |
| 1066 | + // Same cutout pipeline as full-cyl |
| 1067 | + buildPetalSolidsComposite(petal); |
| 1068 | + buildIrisCutoutFromPetalSolid(nPetals); |
| 1069 | +} |
| 1070 | + |
911 | 1071 | void createIRISGeometryFullCylwithDisks(TGeoVolume* motherVolume) |
912 | 1072 | { |
913 | 1073 | if (!motherVolume) { |
|
0 commit comments