Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-27 07:31:51

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2022 Whitney Armstrong
0003 
0004 /** \addtogroup Trackers Trackers
0005  * \brief Type: **BarrelTrackerWithFrame**.
0006  * \author W. Armstrong
0007  *
0008  * \ingroup trackers
0009  *
0010  * @{
0011  */
0012 #include "DD4hep/DetFactoryHelper.h"
0013 #include "DD4hep/Printout.h"
0014 #include "DD4hep/Shapes.h"
0015 #include "DDRec/DetectorData.h"
0016 #include "DDRec/Surface.h"
0017 #include "XML/Layering.h"
0018 #include "XML/Utilities.h"
0019 #include <array>
0020 #include "DD4hepDetectorHelper.h"
0021 
0022 using namespace std;
0023 using namespace dd4hep;
0024 using namespace dd4hep::rec;
0025 using namespace dd4hep::detail;
0026 
0027 /** Barrel Tracker with space frame.
0028  *
0029  * - Optional "support" tag within the detector element.
0030  *
0031  * The shapes are created using createShape which can be one of many basic geomtries.
0032  * See the examples Check_shape_*.xml in
0033  * [dd4hep's examples/ClientTests/compact](https://github.com/AIDASoft/DD4hep/tree/master/examples/ClientTests/compact)
0034  * directory.
0035  *
0036  *
0037  * - Optional "frame" tag within the module element.
0038  *
0039  * \ingroup trackers
0040  *
0041  * \code
0042  * \endcode
0043  *
0044  *
0045  * @author Whitney Armstrong
0046  */
0047 static Ref_t create_BarrelTrackerWithFrame(Detector& description, xml_h e, SensitiveDetector sens) {
0048   typedef vector<PlacedVolume> Placements;
0049   xml_det_t x_det = e;
0050   Material air    = description.air();
0051   int det_id      = x_det.id();
0052   string det_name = x_det.nameStr();
0053   DetElement sdet(det_name, det_id);
0054 
0055   map<string, Volume> volumes;
0056   map<string, Placements> sensitives;
0057   map<string, std::vector<VolPlane>> volplane_surfaces;
0058   map<string, std::array<double, 2>> module_thicknesses;
0059 
0060   PlacedVolume pv;
0061 
0062   // Set detector type flag
0063   dd4hep::xml::setDetectorTypeFlag(x_det, sdet);
0064   auto& params = DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(sdet);
0065 
0066   // Add the volume boundary material if configured
0067   for (xml_coll_t bmat(x_det, _Unicode(boundary_material)); bmat; ++bmat) {
0068     xml_comp_t x_boundary_material = bmat;
0069     DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_boundary_material, params,
0070                                                     "boundary_material");
0071   }
0072 
0073   // dd4hep::xml::Dimension dimensions(x_det.dimensions());
0074   // Tube topVolumeShape(dimensions.rmin(), dimensions.rmax(), dimensions.length() * 0.5);
0075   // Volume assembly(det_name,topVolumeShape,air);
0076   Assembly assembly(det_name);
0077 
0078   sens.setType("tracker");
0079 
0080   // Loop over the suports
0081   for (xml_coll_t su(x_det, _U(support)); su; ++su) {
0082     xml_comp_t x_support     = su;
0083     double support_thickness = getAttrOrDefault(x_support, _U(thickness), 2.0 * mm);
0084     double support_length    = getAttrOrDefault(x_support, _U(length), 2.0 * mm);
0085     double support_rmin      = getAttrOrDefault(x_support, _U(rmin), 2.0 * mm);
0086     double support_zstart    = getAttrOrDefault(x_support, _U(zstart), 2.0 * mm);
0087     std::string support_name =
0088         getAttrOrDefault<std::string>(x_support, _Unicode(name), "support_tube");
0089     std::string support_vis = getAttrOrDefault<std::string>(x_support, _Unicode(vis), "AnlRed");
0090     xml_dim_t pos(x_support.child(_U(position), false));
0091     xml_dim_t rot(x_support.child(_U(rotation), false));
0092     Solid support_solid;
0093     if (x_support.hasChild(_U(shape))) {
0094       xml_comp_t shape(x_support.child(_U(shape)));
0095       string shape_type = shape.typeStr();
0096       support_solid     = xml::createShape(description, shape_type, shape);
0097     } else {
0098       support_solid = Tube(support_rmin, support_rmin + support_thickness, support_length / 2);
0099     }
0100     Transform3D tr =
0101         Transform3D(Rotation3D(), Position(0, 0, (support_zstart + support_length / 2)));
0102     if (pos.ptr() && rot.ptr()) {
0103       Rotation3D rot3D(RotationZYX(rot.z(0), rot.y(0), rot.x(0)));
0104       Position pos3D(pos.x(0), pos.y(0), pos.z(0));
0105       tr = Transform3D(rot3D, pos3D);
0106     } else if (pos.ptr()) {
0107       tr = Transform3D(Rotation3D(), Position(pos.x(0), pos.y(0), pos.z(0)));
0108     } else if (rot.ptr()) {
0109       Rotation3D rot3D(RotationZYX(rot.z(0), rot.y(0), rot.x(0)));
0110       tr = Transform3D(rot3D, Position());
0111     }
0112     Material support_mat = description.material(x_support.materialStr());
0113     Volume support_vol(support_name, support_solid, support_mat);
0114     support_vol.setVisAttributes(description.visAttributes(support_vis));
0115     pv = assembly.placeVolume(support_vol, tr);
0116     // pv = assembly.placeVolume(support_vol, Position(0, 0, support_zstart + support_length / 2));
0117   }
0118 
0119   // loop over the modules
0120   for (xml_coll_t mi(x_det, _U(module)); mi; ++mi) {
0121     xml_comp_t x_mod = mi;
0122     string m_nam     = x_mod.nameStr();
0123 
0124     if (volumes.find(m_nam) != volumes.end()) {
0125       printout(ERROR, "BarrelTrackerWithFrame",
0126                string((string("Module with named ") + m_nam + string(" already exists."))).c_str());
0127       throw runtime_error("Logics error in building modules.");
0128     }
0129 
0130     int ncomponents        = 0;
0131     int sensor_number      = 1;
0132     double total_thickness = 0;
0133 
0134     // Compute module total thickness from components
0135     // add pos z to allow several components being placed at the same z without double-counting the total thickness.
0136     xml_coll_t ci(x_mod, _U(module_component));
0137     for (ci.reset(), total_thickness = 0.0; ci; ++ci) {
0138       xml_comp_t x_pos = xml_comp_t(ci).position(false);
0139       double mod_z_off = 0;
0140       if (x_pos)
0141         mod_z_off = x_pos.z(0);
0142       total_thickness += xml_comp_t(ci).thickness() + mod_z_off;
0143     }
0144     // the module assembly volume
0145     Assembly m_vol(m_nam);
0146     volumes[m_nam] = m_vol;
0147     m_vol.setVisAttributes(description.visAttributes(x_mod.visStr()));
0148 
0149     // Optional module frame.
0150     if (x_mod.hasChild(_U(frame))) {
0151       xml_comp_t m_frame = x_mod.child(_U(frame));
0152       // xmleles[m_nam]  = x_mod;
0153       double frame_thickness = m_frame.thickness();
0154       double frame_width     = m_frame.width();
0155       double frame_height    = getAttrOrDefault<double>(m_frame, _U(height), 5.0 * mm);
0156       double tanth           = frame_height / (frame_width / 2.0);
0157       double costh           = 1. / sqrt(1 + tanth * tanth);
0158       double frame_height2   = frame_height - frame_thickness - frame_thickness / costh;
0159       double frame_width2    = 2.0 * frame_height2 / tanth;
0160 
0161       Trd1 moduleframe_part1(frame_width / 2, 0.001 * mm, m_frame.length() / 2, frame_height / 2);
0162       Trd1 moduleframe_part2(frame_width2 / 2, 0.001 * mm, m_frame.length() / 2 + 0.01 * mm,
0163                              frame_height2 / 2);
0164 
0165       SubtractionSolid moduleframe(moduleframe_part1, moduleframe_part2,
0166                                    Position(0.0, frame_thickness, 0.0));
0167       Volume v_moduleframe(m_nam + "_vol", moduleframe,
0168                            description.material(m_frame.materialStr()));
0169       v_moduleframe.setVisAttributes(description, m_frame.visStr());
0170       m_vol.placeVolume(v_moduleframe,
0171                         Position(0.0, 0.0, frame_height / 2 + total_thickness / 2.0));
0172     }
0173 
0174     double thickness_so_far = 0.0;
0175     double thickness_sum    = -total_thickness / 2.0;
0176     for (xml_coll_t mci(x_mod, _U(module_component)); mci; ++mci, ++ncomponents) {
0177       xml_comp_t x_comp  = mci;
0178       xml_comp_t x_pos   = x_comp.position(false);
0179       xml_comp_t x_rot   = x_comp.rotation(false);
0180       const string c_nam = _toString(ncomponents, "component%d");
0181       Box c_box(x_comp.width() / 2, x_comp.length() / 2, x_comp.thickness() / 2);
0182       Volume c_vol(c_nam, c_box, description.material(x_comp.materialStr()));
0183 
0184       // Utility variable for the relative z-offset based off the previous components
0185       const double zoff = thickness_sum + x_comp.thickness() / 2.0;
0186       if (x_pos && x_rot) {
0187         Position c_pos(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff);
0188         RotationZYX c_rot(x_rot.z(0), x_rot.y(0), x_rot.x(0));
0189         pv = m_vol.placeVolume(c_vol, Transform3D(c_rot, c_pos));
0190       } else if (x_rot) {
0191         Position c_pos(0, 0, zoff);
0192         pv = m_vol.placeVolume(c_vol,
0193                                Transform3D(RotationZYX(x_rot.z(0), x_rot.y(0), x_rot.x(0)), c_pos));
0194       } else if (x_pos) {
0195         pv = m_vol.placeVolume(c_vol, Position(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff));
0196       } else {
0197         pv = m_vol.placeVolume(c_vol, Position(0, 0, zoff));
0198       }
0199       c_vol.setRegion(description, x_comp.regionStr());
0200       c_vol.setLimitSet(description, x_comp.limitsStr());
0201       c_vol.setVisAttributes(description, x_comp.visStr());
0202       // Calculate thickness_so_far before setting sensitive surface so it can be used to calculate inner and outer thicknesses correctly
0203       thickness_sum += x_comp.thickness();
0204       thickness_so_far += x_comp.thickness();
0205       // apply relative offsets in z-position used to stack components side-by-side
0206       if (x_pos) {
0207         thickness_sum += x_pos.z(0);
0208         thickness_so_far += x_pos.z(0);
0209       }
0210       if (x_comp.isSensitive()) {
0211         pv.addPhysVolID("sensor", sensor_number++);
0212         c_vol.setSensitiveDetector(sens);
0213         sensitives[m_nam].push_back(pv);
0214         module_thicknesses[m_nam] = {thickness_so_far - x_comp.thickness() / 2.0,
0215                                      total_thickness - thickness_so_far + x_comp.thickness() / 2.0};
0216 
0217         // -------- create a measurement plane for the tracking surface attched to the sensitive volume -----
0218         Vector3D u(-1., 0., 0.);
0219         Vector3D v(0., -1., 0.);
0220         Vector3D n(0., 0., 1.);
0221         //    Vector3D o( 0. , 0. , 0. ) ;
0222 
0223         // compute the inner and outer thicknesses that need to be assigned to the tracking surface
0224         // depending on wether the support is above or below the sensor
0225         double inner_thickness = module_thicknesses[m_nam][0];
0226         double outer_thickness = module_thicknesses[m_nam][1];
0227 
0228         SurfaceType type(SurfaceType::Sensitive);
0229 
0230         // if( isStripDetector )
0231         //  type.setProperty( SurfaceType::Measurement1D , true ) ;
0232 
0233         VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); //,o ) ;
0234         volplane_surfaces[m_nam].push_back(surf);
0235 
0236         //--------------------------------------------
0237       }
0238     }
0239   }
0240 
0241   // now build the layers
0242   for (xml_coll_t li(x_det, _U(layer)); li; ++li) {
0243     xml_comp_t x_layer  = li;
0244     xml_comp_t x_barrel = x_layer.child(_U(barrel_envelope));
0245     xml_comp_t x_layout = x_layer.child(_U(rphi_layout));
0246     xml_comp_t z_layout = x_layer.child(_U(z_layout)); // Get the <z_layout> element.
0247     int lay_id          = x_layer.id();
0248     string m_nam        = x_layer.moduleStr();
0249     string lay_nam      = det_name + _toString(x_layer.id(), "_layer%d");
0250     Tube lay_tub(x_barrel.inner_r(), x_barrel.outer_r(), x_barrel.z_length() / 2.0);
0251     Volume lay_vol(lay_nam, lay_tub, air); // Create the layer envelope volume.
0252     Position lay_pos(0, 0, getAttrOrDefault(x_barrel, _U(z0), 0.));
0253     lay_vol.setVisAttributes(description.visAttributes(x_layer.visStr()));
0254 
0255     double phi0     = x_layout.phi0();     // Starting phi of first module.
0256     double phi_tilt = x_layout.phi_tilt(); // Phi tilt of a module.
0257     double rc       = x_layout.rc();       // Radius of the module center.
0258     int nphi        = x_layout.nphi();     // Number of modules in phi.
0259     double rphi_dr  = x_layout.dr();       // The delta radius of every other module.
0260     double phi_incr = (M_PI * 2) / nphi;   // Phi increment for one module.
0261     double phic     = phi0;                // Phi of the module center.
0262     double z0       = z_layout.z0();       // Z position of first module in phi.
0263     double nz       = z_layout.nz();       // Number of modules to place in z.
0264     double z_dr     = z_layout.dr();       // Radial displacement parameter, of every other module.
0265 
0266     Volume module_env = volumes[m_nam];
0267     DetElement lay_elt(sdet, lay_nam, lay_id);
0268     Placements& sensVols = sensitives[m_nam];
0269 
0270     // the local coordinate systems of modules in dd4hep and acts differ
0271     // see http://acts.web.cern.ch/ACTS/latest/doc/group__DD4hepPlugins.html
0272     auto& layerParams =
0273         DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(lay_elt);
0274 
0275     for (xml_coll_t lmat(x_layer, _Unicode(layer_material)); lmat; ++lmat) {
0276       xml_comp_t x_layer_material = lmat;
0277       DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_layer_material, layerParams,
0278                                                       "layer_material");
0279     }
0280 
0281     // Z increment for module placement along Z axis.
0282     // Adjust for z0 at center of module rather than
0283     // the end of cylindrical envelope.
0284     double z_incr = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0;
0285     // Starting z for module placement along Z axis.
0286     double module_z = -z0;
0287     int module      = 1;
0288 
0289     // Loop over the number of modules in phi.
0290     for (int ii = 0; ii < nphi; ii++) {
0291       double dx = z_dr * std::cos(phic + phi_tilt); // Delta x of module position.
0292       double dy = z_dr * std::sin(phic + phi_tilt); // Delta y of module position.
0293       double x  = rc * std::cos(phic);              // Basic x module position.
0294       double y  = rc * std::sin(phic);              // Basic y module position.
0295 
0296       // Loop over the number of modules in z.
0297       for (int j = 0; j < nz; j++) {
0298         string module_name = _toString(module, "module%d");
0299         DetElement mod_elt(lay_elt, module_name, module);
0300 
0301         Transform3D tr(RotationZYX(0, ((M_PI / 2) - phic - phi_tilt), -M_PI / 2),
0302                        Position(x, y, module_z));
0303 
0304         pv = lay_vol.placeVolume(module_env, tr);
0305         pv.addPhysVolID("module", module);
0306         mod_elt.setPlacement(pv);
0307         for (size_t ic = 0; ic < sensVols.size(); ++ic) {
0308           PlacedVolume sens_pv = sensVols[ic];
0309           DetElement comp_de(mod_elt, std::string("de_") + sens_pv.volume().name(), module);
0310           comp_de.setPlacement(sens_pv);
0311 
0312           auto& comp_de_params =
0313               DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(comp_de);
0314           comp_de_params.set<string>("axis_definitions", "XYZ");
0315           // comp_de.setAttributes(description, sens_pv.volume(), x_layer.regionStr(), x_layer.limitsStr(),
0316           //                       xml_det_t(xmleles[m_nam]).visStr());
0317           //
0318 
0319           volSurfaceList(comp_de)->push_back(volplane_surfaces[m_nam][ic]);
0320         }
0321 
0322         /// Increase counters etc.
0323         module++;
0324         // Adjust the x and y coordinates of the module.
0325         x += dx;
0326         y += dy;
0327         // Flip sign of x and y adjustments.
0328         dx *= -1;
0329         dy *= -1;
0330         // Add z increment to get next z placement pos.
0331         module_z += z_incr;
0332       }
0333       phic += phi_incr; // Increment the phi placement of module.
0334       rc += rphi_dr;    // Increment the center radius according to dr parameter.
0335       rphi_dr *= -1;    // Flip sign of dr parameter.
0336       module_z = -z0;   // Reset the Z placement parameter for module.
0337     }
0338     // Create the PhysicalVolume for the layer.
0339     pv = assembly.placeVolume(lay_vol, lay_pos); // Place layer in mother
0340     pv.addPhysVolID("layer", lay_id);            // Set the layer ID.
0341     lay_elt.setAttributes(description, lay_vol, x_layer.regionStr(), x_layer.limitsStr(),
0342                           x_layer.visStr());
0343     lay_elt.setPlacement(pv);
0344   }
0345   sdet.setAttributes(description, assembly, x_det.regionStr(), x_det.limitsStr(), x_det.visStr());
0346   assembly.setVisAttributes(description.invisible());
0347   pv = description.pickMotherVolume(sdet).placeVolume(assembly);
0348   pv.addPhysVolID("system", det_id); // Set the subdetector system ID.
0349   sdet.setPlacement(pv);
0350   return sdet;
0351 }
0352 
0353 //@}
0354 // clang-format off
0355 DECLARE_DETELEMENT(epic_BarrelTrackerWithFrame, create_BarrelTrackerWithFrame)
0356 DECLARE_DETELEMENT(epic_TrackerBarrel,   create_BarrelTrackerWithFrame)
0357 DECLARE_DETELEMENT(epic_VertexBarrel,    create_BarrelTrackerWithFrame)
0358 DECLARE_DETELEMENT(epic_InnerMPGDBarrel,       create_BarrelTrackerWithFrame)