Skip to content

Commit a431ffe

Browse files
committed
Add option to define beampipe tracking layer as cross section of arbitrary volume
1 parent 8d623c5 commit a431ffe

File tree

1 file changed

+34
-34
lines changed

1 file changed

+34
-34
lines changed

src/BeamPipeTracking_geo.cpp

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -44,49 +44,50 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s
4444

4545
double sensitive_thickness = 0.1 * mm;
4646
Solid sensitive_solid;
47-
Position disk_position;
47+
Transform3D disk_transform; // Full placement transform
4848

4949
// Check if we should use plane-based cross section (default: false, use cone)
5050
bool use_plane_xs = getAttrOrDefault<bool>(slice_coll, _Unicode(use_cross_section), false);
5151

5252
if (use_plane_xs) {
5353
// Use plane-based cross section
5454

55-
// Get plane definition from XML (normal vector and distance from origin)
56-
double plane_nx = getAttrOrDefault<double>(slice_coll, _Unicode(plane_nx), 0.0);
57-
double plane_ny = getAttrOrDefault<double>(slice_coll, _Unicode(plane_ny), 0.0);
58-
double plane_nz = getAttrOrDefault<double>(slice_coll, _Unicode(plane_nz), 1.0);
59-
double plane_d = getAttrOrDefault<double>(slice_coll, _Unicode(plane_d), 0.0);
55+
// Get plane definition from XML (in world frame)
56+
double plane_x = getAttrOrDefault<double>(slice_coll, _Unicode(plane_x), 0.0);
57+
double plane_y = getAttrOrDefault<double>(slice_coll, _Unicode(plane_y), 0.0);
58+
double plane_z = getAttrOrDefault<double>(slice_coll, _Unicode(plane_z), 0.0);
59+
double plane_yrot = getAttrOrDefault<double>(slice_coll, _Unicode(plane_yrot), 0.0);
6060

61-
// Normalize the plane normal vector
62-
double norm = sqrt(plane_nx*plane_nx + plane_ny*plane_ny + plane_nz*plane_nz);
63-
plane_nx /= norm;
64-
plane_ny /= norm;
65-
plane_nz /= norm;
61+
// Get the mother volume's transformation to world frame
62+
const auto& mother_matrix = mother.nominal().worldTransformation();
63+
const Double_t* translation = mother_matrix.GetTranslation();
64+
const Double_t* rotation = mother_matrix.GetRotationMatrix();
65+
66+
// Build Transform3D from TGeoMatrix
67+
Transform3D mother_to_world(
68+
rotation[0], rotation[1], rotation[2], translation[0],
69+
rotation[3], rotation[4], rotation[5], translation[1],
70+
rotation[6], rotation[7], rotation[8], translation[2]
71+
);
72+
73+
// Transform the plane position and rotation from world frame to mother's local frame
74+
Position plane_pos_world(plane_x, plane_y, plane_z);
75+
RotationY plane_rot_world(plane_yrot);
76+
Transform3D plane_transform_world(plane_rot_world, plane_pos_world);
77+
78+
// Apply inverse transformation to get plane in mother's local coordinates
79+
disk_transform = mother_to_world.Inverse() * plane_transform_world;
6680

6781
// Get maximum dimension for cutting box
6882
double max_dim = getAttrOrDefault<double>(slice_coll, _Unicode(max_dimension), 1.0 * m);
6983

7084
// Create a thin box perpendicular to the plane normal
7185
Box cutting_box(max_dim, max_dim, sensitive_thickness / 2);
72-
73-
// Calculate rotation to align box with plane normal
74-
// Default box normal is along Z, rotate to align with plane normal
75-
RotationZYX rotation;
76-
if (fabs(plane_nz - 1.0) > 1e-6 || fabs(plane_nx) > 1e-6 || fabs(plane_ny) > 1e-6) {
77-
// Calculate rotation angles to align Z-axis with plane normal
78-
double theta = acos(plane_nz); // angle from Z axis
79-
double phi = atan2(plane_ny, plane_nx); // angle in XY plane
80-
rotation = RotationZYX(0.0, theta, phi);
81-
}
82-
83-
// Position the cutting plane at distance plane_d along the normal
84-
Position plane_pos(plane_nx * plane_d, plane_ny * plane_d, plane_nz * plane_d);
85-
86-
// Create intersection of mother volume with the cutting box
87-
sensitive_solid = IntersectionSolid(mother_vol.solid(), cutting_box,
88-
Transform3D(rotation, plane_pos));
89-
disk_position = Position(0.0, 0.0, 0.0);
86+
87+
// Create intersection of cutting box with mother volume (reversed order to preserve rotation)
88+
// Apply the inverse transform to the second operand (mother) to express it in the box frame
89+
sensitive_solid = IntersectionSolid(cutting_box, mother_vol.solid(), disk_transform.Inverse());
90+
9091

9192
} else {
9293
// Use cone segment (default behavior)
@@ -106,24 +107,23 @@ static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector s
106107
}
107108

108109
sensitive_solid = ConeSegment(sensitive_thickness / 2, 0.0, rOuter2, 0.0, rEnd);
109-
disk_position = Position(0.0, 0.0, zPos);
110+
disk_transform = Transform3D(Rotation3D(), Position(0.0, 0.0, zPos));
110111
}
111112

112113
Volume v_start_disk("v_start_disk_" + motherName, sensitive_solid, m_Vacuum);
113114
v_start_disk.setSensitiveDetector(sens);
114115

115-
auto disk_placement = mother_vol.placeVolume(v_start_disk, disk_position);
116+
auto disk_placement = mother_vol.placeVolume(v_start_disk, disk_transform);
116117
disk_placement.addPhysVolID("end", detStart);
117118
disk_placement.addPhysVolID("pipe", pipe_id);
118119
disk_placement.addPhysVolID("system", det_id);
119120

120-
DetElement slice_element(sdet, slice_name, pipe_id);
121+
DetElement slice_element(mother, slice_name, pipe_id);
121122

122123
slice_element.setPlacement(disk_placement);
123-
description.declareParent(slice_name, mother);
124124
}
125125

126-
auto pv_assembly = description.worldVolume().placeVolume(assembly, Position(0.0, 0.0, 0.0));
126+
auto pv_assembly = description.worldVolume().placeVolume(assembly);
127127
pv_assembly.addPhysVolID("system", det_id);
128128
sdet.setPlacement(pv_assembly);
129129

0 commit comments

Comments
 (0)