Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-25 09:25:09

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2022-2025 Simon Gardner
0003 
0004 #include "DD4hep/DetFactoryHelper.h"
0005 #include "DD4hep/OpticalSurfaces.h"
0006 #include "DD4hep/Printout.h"
0007 #include "DDRec/DetectorData.h"
0008 #include "DDRec/Surface.h"
0009 
0010 //////////////////////////////////////////////////
0011 // Far backwards vacuum drift volume
0012 //////////////////////////////////////////////////
0013 
0014 using namespace std;
0015 using namespace dd4hep;
0016 using namespace dd4hep::rec;
0017 
0018 // Helper function to make the tagger tracker detectors
0019 static void Make_Tagger(Detector& desc, xml_coll_t& mod, Assembly& env);
0020 
0021 static Ref_t create_detector(Detector& desc, xml_h e, SensitiveDetector /* sens */) {
0022 
0023   xml_det_t x_det = e;
0024   string detName  = x_det.nameStr();
0025   int detID       = x_det.id();
0026 
0027   DetElement det(detName, detID);
0028 
0029   string vis_name = dd4hep::getAttrOrDefault<std::string>(x_det, _Unicode(vis), "BackwardsBox");
0030 
0031   // Dimensions of main beamline pipe
0032   xml::Component dim = x_det.child(_Unicode(dimensions));
0033   double WidthL      = dim.attr<double>(_Unicode(xL));
0034   double WidthR      = dim.attr<double>(_Unicode(xR));
0035 
0036   double Width     = (WidthL + WidthR) / 2;
0037   double Height    = dim.y();
0038   double Thickness = dim.z();
0039 
0040   // Materials
0041   Material Vacuum = desc.material("Vacuum");
0042   Material Steel  = desc.material("StainlessSteelSAE304");
0043 
0044   // Central focal point of the geometry
0045   xml::Component pos = x_det.child(_Unicode(focus));
0046   double off         = pos.z();
0047 
0048   // Beamline rotation
0049   xml_dim_t rot = x_det.rotation();
0050 
0051   // Beampipe thickness
0052   double wall = dd4hep::getAttrOrDefault<double>(x_det, _Unicode(wall), 1 * mm);
0053 
0054   // Make bounding box to make IntersectionSolid with other components
0055   xml::Component BB = x_det.child(_Unicode(bounding));
0056   double BB_MinX    = BB.xmin();
0057   double BB_MinY    = BB.ymin();
0058   double BB_MinZ    = BB.zmin();
0059   double BB_MaxX    = BB.xmax();
0060   double BB_MaxY    = BB.ymax();
0061   double BB_MaxZ    = BB.zmax();
0062 
0063   double BB_X = abs(BB_MaxX - BB_MinX);
0064   double BB_Y = abs(BB_MaxY - BB_MinY);
0065   double BB_Z = abs(BB_MaxZ - BB_MinZ);
0066 
0067   Box Far_Backwards_Box(BB_X, BB_Y, BB_Z);
0068 
0069   // Entry box geometry description joining magnet, taggers and lumi
0070   xml::Component EB = x_det.child(_Unicode(exitdim));
0071   double ED_X       = EB.x();
0072   double ED_Y       = EB.y();
0073   double ED_Z       = off - EB.attr<double>(_Unicode(lumiZ));
0074   double Lumi_R     = EB.attr<double>(_Unicode(lumiR));
0075 
0076   // Maximum theta to exit the dipole from
0077   double exitTheta = EB.attr<double>(_Unicode(maxTheta));
0078 
0079   // Generic box for making intersection solid with
0080   double xbox = 10 * m;
0081   double ybox = 10 * m;
0082   double zbox = 50 * m;
0083 
0084   Box Cut_Box(xbox, ybox, zbox);
0085 
0086   // Central pipe box
0087   //Tube Extended_Beam_Box(Width,Width+wall,Thickness); // More realistic tube pipe
0088   Box Extended_Beam_Box(Width + wall, Height + wall, Thickness); // Simpler box pipe
0089 
0090   // Central vacuum box
0091   //Tube Extended_Vacuum_Box(0,Width,Thickness); // More realistic tube pipe
0092   Box Extended_Vacuum_Box(Width, Height, Thickness); // Simpler box pipe
0093 
0094   Solid Wall_Box   = Extended_Beam_Box;
0095   Solid Vacuum_Box = Extended_Vacuum_Box;
0096 
0097   Assembly DetAssembly("Tagger_vacuum_assembly");
0098 
0099   //-----------------------------------------------------------------
0100   // Add Tagger box containers and vacuum box extension to main beamline for modules
0101   //-----------------------------------------------------------------
0102   for (xml_coll_t mod(x_det, _Unicode(module)); mod; ++mod) {
0103 
0104     int moduleID      = dd4hep::getAttrOrDefault<int>(mod, _Unicode(id), 0);
0105     string moduleName = dd4hep::getAttrOrDefault<std::string>(mod, _Unicode(name), "Tagger0");
0106 
0107     xml_dim_t mod_pos_global = mod.child(_U(position));
0108     xml_dim_t mod_rot_global = mod.child(_U(rotation));
0109     Position mod_pos(mod_pos_global.x(), mod_pos_global.y(), mod_pos_global.z());
0110     Position vac_pos(mod_pos_global.x() + wall / 2 * cos(mod_rot_global.theta()),
0111                      mod_pos_global.y(),
0112                      mod_pos_global.z() + wall / 2 * sin(mod_rot_global.theta()));
0113     RotationY mod_rot(mod_rot_global.theta() - rot.theta());
0114 
0115     // Size of the actual tagger box, replicated in BackwardsTagger
0116     xml_dim_t moddim = mod.child(_Unicode(dimensions));
0117     double vac_w     = moddim.x() / 2;
0118     double vac_h     = moddim.y() / 2;
0119     double vac_l     = moddim.z() / 2;
0120 
0121     // Width and height of box volume
0122     auto box_w = vac_w + wall;
0123     auto box_h = vac_h + wall;
0124 
0125     Box TagWallBox(box_w, box_h, vac_l);
0126     Box TagVacBox(
0127         vac_w + wall / 2, vac_h,
0128         vac_l); // Vacuum box extends into wall on beamline side to ensure no residual material
0129 
0130     Wall_Box   = UnionSolid(Wall_Box, TagWallBox, Transform3D(mod_rot, mod_pos));
0131     Vacuum_Box = UnionSolid(Vacuum_Box, TagVacBox, Transform3D(mod_rot, vac_pos));
0132 
0133     Assembly TaggerAssembly("Tagger_module_assembly");
0134 
0135     PlacedVolume pv_mod = DetAssembly.placeVolume(
0136         TaggerAssembly,
0137         Transform3D(mod_rot,
0138                     mod_pos + Position(-vac_l * sin(mod_rot_global.theta() - rot.theta()), 0,
0139                                        -vac_l * cos(mod_rot_global.theta() - rot.theta()))));
0140     DetElement moddet(det, moduleName, moduleID);
0141     pv_mod.addPhysVolID("module", moduleID);
0142     moddet.setPlacement(pv_mod);
0143 
0144     Make_Tagger(desc, mod, TaggerAssembly);
0145   }
0146 
0147   //-----------------------------------------------------------------
0148   // Cut off any vacuum right of the main beamline
0149   //-----------------------------------------------------------------
0150 
0151   Wall_Box   = IntersectionSolid(Wall_Box, Cut_Box, Position(-xbox + Width + wall, 0, 0));
0152   Vacuum_Box = IntersectionSolid(Vacuum_Box, Cut_Box, Position(-xbox + Width, 0, 0));
0153 
0154   //-----------------------------------------------------------------
0155   // Luminosity connecting box
0156   //-----------------------------------------------------------------
0157   bool addLumi = dd4hep::getAttrOrDefault<bool>(x_det, _Unicode(lumi), true);
0158 
0159   if (addLumi) {
0160 
0161     Box Entry_Beam_Box(ED_X + wall, ED_Y + wall, ED_Z);
0162     Box Entry_Vacuum_Box(ED_X, ED_Y, ED_Z - wall);
0163     Tube Lumi_Exit(0, Lumi_R, ED_Z);
0164 
0165     // Future angled exit window and more realistic tube shaped pipe.
0166     // double angle = -pi/4;
0167     // CutTube Entry_Beam_Box  (ED_X, ED_X + wall, ED_Z,        0,2*pi, sin(angle),0,cos(angle), 0,0,1);
0168     // CutTube Entry_Vacuum_Box(0,    ED_X,        ED_Z - wall, 0,2*pi, sin(angle),0,cos(angle), 0,0,1);
0169     // CutTube Lumi_Exit       (0,    Lumi_R,      ED_Z,        0,2*pi, sin(angle),0,cos(angle), 0,0,1);
0170 
0171     // Add entry boxes to main beamline volume
0172     Wall_Box   = UnionSolid(Wall_Box, Entry_Beam_Box, Transform3D(RotationY(-rot.theta())));
0173     Vacuum_Box = UnionSolid(Vacuum_Box, Entry_Vacuum_Box, Transform3D(RotationY(-rot.theta())));
0174     Vacuum_Box = UnionSolid(Vacuum_Box, Lumi_Exit, Transform3D(RotationY(-rot.theta())));
0175   }
0176 
0177   //-----------------------------------------------------------------
0178   // Restrict tagger boxes into region defined by exitTheta from the dipole magnet
0179   //-----------------------------------------------------------------
0180   double exitDist = BB_MinZ - off;
0181   double cutX     = (ED_X - exitDist * tan(-rot.theta())) * cos(rot.theta());
0182   double cutZ =
0183       (ED_X - exitDist * tan(-rot.theta())) * sin(rot.theta()) + exitDist * cos(rot.theta());
0184   double cutXwall = (ED_X - wall - exitDist * tan(-rot.theta())) * cos(rot.theta());
0185   double cutZwall =
0186       (ED_X - wall - exitDist * tan(-rot.theta())) * sin(rot.theta()) + exitDist * cos(rot.theta());
0187 
0188   Wall_Box = IntersectionSolid(Wall_Box, Cut_Box,
0189                                Transform3D(RotationY(exitTheta), Position(xbox - cutX, 0, cutZ)));
0190   Vacuum_Box =
0191       IntersectionSolid(Vacuum_Box, Cut_Box,
0192                         Transform3D(RotationY(exitTheta), Position(xbox - cutXwall, 0, cutZwall)));
0193 
0194   //-----------------------------------------------------------------
0195   // Cut solids so they are only in the far backwards box
0196   //-----------------------------------------------------------------
0197   RotationY rotate2(-rot.theta());
0198   Position position(0, 0, (exitDist - BB_Z) / cos(rot.theta()));
0199 
0200   IntersectionSolid Wall_Box_Sub(Wall_Box, Far_Backwards_Box, Transform3D(rotate2, position));
0201   IntersectionSolid Vacuum_Box_Sub(Vacuum_Box, Far_Backwards_Box, Transform3D(rotate2, position));
0202   SubtractionSolid Wall_Box_Out(Wall_Box_Sub, Vacuum_Box_Sub);
0203 
0204   Volume vacVol("TaggerStation_Vacuum", Vacuum_Box_Sub, Vacuum);
0205   vacVol.setVisAttributes(desc.visAttributes("BackwardsVac"));
0206   vacVol.placeVolume(DetAssembly);
0207 
0208   Volume wallVol("TaggerStation_Container", Wall_Box_Out, Steel);
0209   wallVol.setVisAttributes(desc.visAttributes(vis_name));
0210 
0211   Assembly backAssembly(detName + "_assembly");
0212   backAssembly.placeVolume(wallVol);
0213   backAssembly.placeVolume(vacVol);
0214 
0215   // placement in mother volume
0216   Transform3D tr(RotationY(rot.theta()), Position(pos.x(), pos.y(), pos.z()));
0217   PlacedVolume detPV = desc.pickMotherVolume(det).placeVolume(backAssembly, tr);
0218   detPV.addPhysVolID("system", detID);
0219 
0220   det.setPlacement(detPV);
0221 
0222   return det;
0223 }
0224 
0225 static void Make_Tagger(Detector& desc, xml_coll_t& mod, Assembly& env) {
0226 
0227   xml_dim_t moddim = mod.child(_Unicode(dimensions));
0228   double tag_w     = moddim.x() / 2;
0229   double tag_h     = moddim.y() / 2;
0230 
0231   double window_thickness = 0;
0232 
0233   // Add vacuum exit window
0234   for (xml_coll_t lay(mod, _Unicode(windowLayer)); lay; ++lay) {
0235 
0236     string layerType = dd4hep::getAttrOrDefault<std::string>(lay, _Unicode(type), "window");
0237     string layerVis =
0238         dd4hep::getAttrOrDefault<std::string>(lay, _Unicode(vis), "FFTrackerShieldingVis");
0239     double layerRot = dd4hep::getAttrOrDefault<double>(lay, _Unicode(angle), 0);
0240     double layerThickness =
0241         dd4hep::getAttrOrDefault<double>(lay, _Unicode(sensor_thickness), 1 * mm);
0242     string layerMaterial = dd4hep::getAttrOrDefault<std::string>(lay, _Unicode(material), "Copper");
0243 
0244     window_thickness = layerThickness;
0245 
0246     Material WindowMaterial = desc.material(layerMaterial);
0247 
0248     RotationY rotate(layerRot);
0249 
0250     Box Window_Box(tag_w, tag_h, layerThickness / 2);
0251     Volume layVol("WindowVolume", Window_Box, WindowMaterial);
0252     layVol.setVisAttributes(desc.visAttributes(layerVis));
0253 
0254     env.placeVolume(layVol, Position(0, 0, layerThickness / 2));
0255 
0256     // Currently only one "window" layer implemented
0257     break;
0258   }
0259 
0260   // Add foil layer angled to reduce beam impedance
0261   for (xml_coll_t lay(mod, _Unicode(foilLayer)); lay; ++lay) {
0262 
0263     string layerType = dd4hep::getAttrOrDefault<std::string>(lay, _Unicode(type), "foil");
0264     string layerVis =
0265         dd4hep::getAttrOrDefault<std::string>(lay, _Unicode(vis), "FFTrackerShieldingVis");
0266     double layerRot = dd4hep::getAttrOrDefault<double>(lay, _Unicode(angle), 45 * deg);
0267     double layerThickness =
0268         dd4hep::getAttrOrDefault<double>(lay, _Unicode(sensor_thickness), 100 * um);
0269     string layerMaterial = dd4hep::getAttrOrDefault<std::string>(lay, _Unicode(material), "Copper");
0270 
0271     Material FoilMaterial = desc.material(layerMaterial);
0272 
0273     RotationY rotate(layerRot);
0274 
0275     Box Foil_Box(tag_w / cos(layerRot) - 0.5 * layerThickness * tan(layerRot), tag_h,
0276                  layerThickness / 2);
0277     Volume layVol("FoilVolume", Foil_Box, FoilMaterial);
0278     layVol.setVisAttributes(desc.visAttributes(layerVis));
0279 
0280     env.placeVolume(layVol,
0281                     Transform3D(rotate, Position(0, 0, window_thickness + tag_w * tan(layerRot))));
0282 
0283     // Currently only one "foil" layer implemented
0284     break;
0285   }
0286 }
0287 
0288 DECLARE_DETELEMENT(FarBackwardVacuum, create_detector)