Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:28:31

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2024-2025 Simon Gardner
0003 
0004 //==========================================================================
0005 //
0006 // Places thin sensitive slices of vacuum along a beam pipe
0007 //
0008 //==========================================================================
0009 
0010 #include "DD4hep/DetFactoryHelper.h"
0011 #include "DD4hep/Printout.h"
0012 #include "TMath.h"
0013 #include <XML/Helper.h>
0014 
0015 using namespace std;
0016 using namespace dd4hep;
0017 
0018 static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) {
0019 
0020   using namespace ROOT::Math;
0021   xml_det_t x_det   = e;
0022   string det_name   = x_det.nameStr();
0023   int det_id        = x_det.id();
0024   Material m_Vacuum = description.material("Vacuum");
0025   string vis_name   = dd4hep::getAttrOrDefault<std::string>(x_det, _Unicode(vis), "BeamPipeVis");
0026 
0027   sens.setType("tracker");
0028 
0029   DetElement sdet(det_name, det_id);
0030   Assembly assembly(det_name + "_assembly");
0031 
0032   // Loop over each requested slice from the geometry description
0033   for (xml_coll_t slice_coll(x_det, _Unicode(slice)); slice_coll; slice_coll++) { // pipes
0034 
0035     string grandmotherName = slice_coll.attr<string>(_Unicode(grandmother));
0036     string motherName      = slice_coll.attr<string>(_Unicode(mother));
0037     bool detStart          = getAttrOrDefault<bool>(slice_coll, _Unicode(end), true);
0038     int pipe_id            = getAttrOrDefault<int>(slice_coll, _Unicode(pipe_id), 0);
0039     string slice_name      = slice_coll.attr<string>(_Unicode(name));
0040     DetElement mother      = description.detector(grandmotherName).child(motherName);
0041 
0042     // Get the mother volume
0043     Volume mother_vol = mother.volume();
0044 
0045     double sensitive_thickness = 0.1 * mm;
0046     Solid sensitive_solid;
0047     Transform3D disk_transform; // Full placement transform
0048 
0049     // Check if we should use plane-based cross section (default: false, use cone)
0050     bool use_plane_xs = getAttrOrDefault<bool>(slice_coll, _Unicode(use_cross_section), false);
0051 
0052     if (use_plane_xs) {
0053 
0054       // Get plane definition from XML (in world frame)
0055       double plane_x    = getAttrOrDefault<double>(slice_coll, _Unicode(plane_x), 0.0);
0056       double plane_y    = getAttrOrDefault<double>(slice_coll, _Unicode(plane_y), 0.0);
0057       double plane_z    = getAttrOrDefault<double>(slice_coll, _Unicode(plane_z), 0.0);
0058       double plane_yrot = getAttrOrDefault<double>(slice_coll, _Unicode(plane_yrot), 0.0);
0059 
0060       // Get the mother volume's transformation to world frame
0061       auto mother_matrix          = mother.nominal().worldTransformation();
0062       const Double_t* translation = mother_matrix.GetTranslation();
0063       const Double_t* rotation    = mother_matrix.GetRotationMatrix();
0064 
0065       // Build Transform3D from TGeoMatrix
0066       Transform3D mother_to_world(rotation[0], rotation[1], rotation[2], translation[0],
0067                                   rotation[3], rotation[4], rotation[5], translation[1],
0068                                   rotation[6], rotation[7], rotation[8], translation[2]);
0069 
0070       // Transform the plane position and rotation from world frame to mother's local frame
0071       Position plane_pos_world(plane_x, plane_y, plane_z);
0072       RotationY plane_rot_world(plane_yrot);
0073       Transform3D plane_transform_world(plane_rot_world, plane_pos_world);
0074 
0075       // Apply inverse transformation to get plane in mother's local coordinates
0076       disk_transform = mother_to_world.Inverse() * plane_transform_world;
0077 
0078       // Get maximum dimension for cutting box
0079       double max_dim = getAttrOrDefault<double>(slice_coll, _Unicode(max_dimension), 1.0 * m);
0080 
0081       // Create a thin box perpendicular to the plane normal
0082       Box cutting_box(max_dim, max_dim, sensitive_thickness / 2);
0083 
0084       // Create intersection of cutting box with mother volume (reversed order to preserve rotation)
0085       // Apply the inverse transform to the second operand (mother) to express it in the box frame
0086       sensitive_solid =
0087           IntersectionSolid(cutting_box, mother_vol.solid(), disk_transform.Inverse());
0088 
0089     } else {
0090       // Use cone segment (default behavior before outline of xs is implemented in benchmark)
0091       ConeSegment mother_shape = mother_vol.solid();
0092 
0093       // Get the parameters of the mother volume
0094       double rOuter1 = mother_shape.rMax1();
0095       double rOuter2 = mother_shape.rMax2();
0096       double length  = 2 * mother_shape.dZ();
0097 
0098       //Calculate R of cone after sensitive layer
0099       double rEnd = rOuter2 - (rOuter2 - rOuter1) * sensitive_thickness / length;
0100       double zPos = length / 2.0 - sensitive_thickness / 2.0;
0101       if (detStart) {
0102         rEnd = rOuter1 - (rOuter1 - rOuter2) * sensitive_thickness / length;
0103         zPos = -length / 2.0 + sensitive_thickness / 2.0;
0104       }
0105 
0106       sensitive_solid = ConeSegment(sensitive_thickness / 2, 0.0, rOuter2, 0.0, rEnd);
0107       disk_transform  = Transform3D(Rotation3D(), Position(0.0, 0.0, zPos));
0108     }
0109 
0110     Volume v_start_disk("v_start_disk_" + motherName, sensitive_solid, m_Vacuum);
0111     v_start_disk.setSensitiveDetector(sens);
0112 
0113     auto disk_placement = mother_vol.placeVolume(v_start_disk, disk_transform);
0114     disk_placement.addPhysVolID("end", detStart);
0115     disk_placement.addPhysVolID("pipe", pipe_id);
0116     disk_placement.addPhysVolID("system", det_id);
0117 
0118     DetElement slice_element(mother, slice_name, pipe_id);
0119 
0120     slice_element.setPlacement(disk_placement);
0121   }
0122 
0123   auto pv_assembly = description.worldVolume().placeVolume(assembly);
0124   pv_assembly.addPhysVolID("system", det_id);
0125   sdet.setPlacement(pv_assembly);
0126 
0127   return sdet;
0128 }
0129 
0130 DECLARE_DETELEMENT(BeamPipeTracking, create_detector)