Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 07:53:58

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2022 - 2024, Whitney Armstrong, Chun Yuen Tsang
0003 
0004 /** \addtogroup Trackers Trackers
0005  * \brief Type: **TOFBarrel**.
0006  * \author W. Armstrong
0007  * \modified by C.Y Tsang 3rd Aug, 2024
0008  *
0009  * \ingroup trackers
0010  *
0011  * @{
0012  */
0013 #include "DD4hep/DetFactoryHelper.h"
0014 #include "DD4hep/Printout.h"
0015 #include "DD4hep/Shapes.h"
0016 #include "DDRec/DetectorData.h"
0017 #include "DDRec/Surface.h"
0018 #include "XML/Layering.h"
0019 #include "XML/Utilities.h"
0020 #include <array>
0021 #include <iostream>
0022 #include "DD4hepDetectorHelper.h"
0023 
0024 using namespace std;
0025 using namespace dd4hep;
0026 using namespace dd4hep::rec;
0027 using namespace dd4hep::detail;
0028 
0029 /** Barrel Tracker with space frame.
0030  *
0031  * - Optional "support" tag within the detector element.
0032  *
0033  * The shapes are created using createShape which can be one of many basic geomtries.
0034  * See the examples Check_shape_*.xml in
0035  * [dd4hep's examples/ClientTests/compact](https://github.com/AIDASoft/DD4hep/tree/master/examples/ClientTests/compact)
0036  * directory.
0037  *
0038  *
0039  * - Optional "frame" tag within the module element.
0040  *
0041  * \ingroup trackers
0042  *
0043  * \code
0044  * \endcode
0045  *
0046  *
0047  * @author Whitney Armstrong
0048  */
0049 static Ref_t create_TOFBarrel(Detector& description, xml_h e, SensitiveDetector sens) {
0050   typedef vector<PlacedVolume> Placements;
0051   xml_det_t x_det = e;
0052   Material air    = description.air();
0053   int det_id      = x_det.id();
0054   string det_name = x_det.nameStr();
0055   DetElement sdet(det_name, det_id);
0056 
0057   map<string, Volume> volumes;
0058   map<string, Placements> sensitives;
0059   map<string, std::vector<VolPlane>> volplane_surfaces;
0060   map<string, std::array<double, 2>> module_thicknesses;
0061 
0062   PlacedVolume pv;
0063 
0064   // Set detector type flag
0065   dd4hep::xml::setDetectorTypeFlag(x_det, sdet);
0066   auto& params = DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(sdet);
0067 
0068   // Add the volume boundary material if configured
0069   for (xml_coll_t bmat(x_det, _Unicode(boundary_material)); bmat; ++bmat) {
0070     xml_comp_t x_boundary_material = bmat;
0071     DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_boundary_material, params,
0072                                                     "boundary_material");
0073   }
0074 
0075   // dd4hep::xml::Dimension dimensions(x_det.dimensions());
0076   // Tube topVolumeShape(dimensions.rmin(), dimensions.rmax(), dimensions.length() * 0.5);
0077   // Volume assembly(det_name,topVolumeShape,air);
0078   Assembly assembly(det_name);
0079 
0080   sens.setType("tracker");
0081 
0082   // Loop over the suports
0083   for (xml_coll_t su(x_det, _U(support)); su; ++su) {
0084     xml_comp_t x_support     = su;
0085     double support_thickness = getAttrOrDefault(x_support, _U(thickness), 2.0 * mm);
0086     double support_length    = getAttrOrDefault(x_support, _U(length), 2.0 * mm);
0087     double support_rmin      = getAttrOrDefault(x_support, _U(rmin), 2.0 * mm);
0088     double support_zstart    = getAttrOrDefault(x_support, _U(zstart), 2.0 * mm);
0089     std::string support_name =
0090         getAttrOrDefault<std::string>(x_support, _Unicode(name), "support_tube");
0091     std::string support_vis = getAttrOrDefault<std::string>(x_support, _Unicode(vis), "AnlRed");
0092     xml_dim_t pos(x_support.child(_U(position), false));
0093     xml_dim_t rot(x_support.child(_U(rotation), false));
0094     Solid support_solid;
0095     if (x_support.hasChild(_U(shape))) {
0096       xml_comp_t shape(x_support.child(_U(shape)));
0097       string shape_type = shape.typeStr();
0098       support_solid     = xml::createShape(description, shape_type, shape);
0099     } else {
0100       support_solid = Tube(support_rmin, support_rmin + support_thickness, support_length / 2);
0101     }
0102     Transform3D tr =
0103         Transform3D(Rotation3D(), Position(0, 0, (support_zstart + support_length / 2)));
0104     if (pos.ptr() && rot.ptr()) {
0105       Rotation3D rot3D(RotationZYX(rot.z(0), rot.y(0), rot.x(0)));
0106       Position pos3D(pos.x(0), pos.y(0), pos.z(0));
0107       tr = Transform3D(rot3D, pos3D);
0108     } else if (pos.ptr()) {
0109       tr = Transform3D(Rotation3D(), Position(pos.x(0), pos.y(0), pos.z(0)));
0110     } else if (rot.ptr()) {
0111       Rotation3D rot3D(RotationZYX(rot.z(0), rot.y(0), rot.x(0)));
0112       tr = Transform3D(rot3D, Position());
0113     }
0114     Material support_mat = description.material(x_support.materialStr());
0115     Volume support_vol(support_name, support_solid, support_mat);
0116     support_vol.setVisAttributes(description.visAttributes(support_vis));
0117     pv = assembly.placeVolume(support_vol, tr);
0118     // pv = assembly.placeVolume(support_vol, Position(0, 0, support_zstart + support_length / 2));
0119   }
0120 
0121   // loop over the modules
0122   for (xml_coll_t mi(x_det, _U(module)); mi; ++mi) {
0123     xml_comp_t x_mod = mi;
0124     string m_nam     = x_mod.nameStr();
0125 
0126     if (volumes.find(m_nam) != volumes.end()) {
0127       printout(ERROR, "TOFBarrel",
0128                string((string("Module with named ") + m_nam + string(" already exists."))).c_str());
0129       throw runtime_error("Logics error in building modules.");
0130     }
0131 
0132     int sensor_number      = 1;
0133     double total_thickness = 0;
0134 
0135     // Compute module total thickness from components
0136     xml_coll_t ci(x_mod, _U(module_component));
0137     for (ci.reset(), total_thickness = 0.0; ci; ++ci) {
0138       if (!getAttrOrDefault<bool>(xml_comp_t(ci), _Unicode(keep_layer), false))
0139         total_thickness += xml_comp_t(ci).thickness();
0140     }
0141     // the module assembly volume
0142     Assembly m_vol(m_nam);
0143     volumes[m_nam] = m_vol;
0144     m_vol.setVisAttributes(description.visAttributes(x_mod.visStr()));
0145 
0146     // Optional module frame.
0147     if (x_mod.hasChild(_U(frame))) {
0148       xml_comp_t m_frame = x_mod.child(_U(frame));
0149       // xmleles[m_nam]  = x_mod;
0150       double frame_thickness = m_frame.thickness();
0151       double frame_width     = m_frame.width();
0152       double frame_height    = getAttrOrDefault<double>(m_frame, _U(height), 5.0 * mm);
0153       double tanth           = frame_height / (frame_width / 2.0);
0154       double costh           = 1. / sqrt(1 + tanth * tanth);
0155       double frame_height2   = frame_height - frame_thickness - frame_thickness / costh;
0156       double frame_width2    = 2.0 * frame_height2 / tanth;
0157 
0158       Trd1 moduleframe_part1(frame_width / 2, 0.001 * mm, m_frame.length() / 2, frame_height / 2);
0159       Trd1 moduleframe_part2(frame_width2 / 2, 0.001 * mm, m_frame.length() / 2 + 0.01 * mm,
0160                              frame_height2 / 2);
0161 
0162       SubtractionSolid moduleframe(moduleframe_part1, moduleframe_part2,
0163                                    Position(0.0, frame_thickness, 0.0));
0164       Volume v_moduleframe(m_nam + "_vol", moduleframe,
0165                            description.material(m_frame.materialStr()));
0166       v_moduleframe.setVisAttributes(description, m_frame.visStr());
0167       m_vol.placeVolume(v_moduleframe,
0168                         Position(0.0, 0.0, frame_height / 2 + total_thickness / 2.0));
0169     }
0170 
0171     double thickness_so_far = 0.0;
0172     double thickness_sum    = -total_thickness / 2.0;
0173     for (xml_coll_t mci(x_mod, _U(module_component)); mci; ++mci) {
0174       xml_comp_t x_comp = mci;
0175       xml_comp_t x_pos  = x_comp.position(false);
0176       xml_comp_t x_rot  = x_comp.rotation(false);
0177       auto make_box     = [&](double width, double length, double thickness, double pos_x = 0,
0178                           double pos_y = 0, double pos_z = 0, double rot_x = 0, double rot_y = 0,
0179                           double rot_z = 0, bool z_stacking = true, int segmentation_id = 0,
0180                           const std::string& suffix = "") {
0181         // Utility variable for the relative z-offset based off the previous components
0182         const double zoff = thickness_sum + thickness / 2.0;
0183 
0184         const string c_nam = "component_" + x_comp.nameStr() + suffix;
0185         Box c_box(width / 2, length / 2, thickness / 2);
0186         Volume c_vol;
0187 
0188         if (x_comp.hasChild(_Unicode(cooling_pipe))) {
0189           /*************************************
0190            * Illustraction of pipe parameters
0191            *+----------------------------------------------------
0192            *|   ---> y
0193            *|  |
0194            *|  |            ----------------------------
0195            *|  v         /                           ^
0196            *|  x      /                              v pipe_max_r
0197            *|        /       ---------------------------
0198            *|       /      /
0199            *|     /      /
0200            *|    /     /                        ---------------------x (center of the module)
0201            *|   /     /         -pipe_offset_x  ^                    |
0202            *|  |     |                          v                    |
0203            *|  |  |<-+------>x<------------------------------------->|
0204            *|  |     |bend_r                   bend_y
0205            *|   \     \
0206            *|    \      \
0207            *|     \      \
0208            *|       \      \
0209            *|         \      ---------------------------
0210            *|          \
0211            *|             \
0212            *|                ---------------------------
0213            *|
0214            *+---------------------------------------------------
0215            * pipe_min_r (not shown) is the radius of the inside of the cooling pipe
0216            * pipe_max_r is the radius of the outside of the cooling pipe
0217            * pipe_offset_x and bend_y are defined with respect to the center of the module
0218            **********************************/
0219           xml_comp_t ci_tube   = x_comp.child(_Unicode(cooling_pipe));
0220           double pipe_max_r    = ci_tube.rmax();
0221           double pipe_min_r    = ci_tube.rmin();
0222           double bend_r        = getAttrOrDefault<double>(ci_tube, _Unicode(bend_r), pipe_max_r);
0223           double pipe_offset_x = getAttrOrDefault<double>(ci_tube, _Unicode(offset_x), 0);
0224           double bend_y =
0225               getAttrOrDefault<double>(ci_tube, _Unicode(bend_y), length / 2 - bend_r - pipe_max_r);
0226           std::string direction =
0227               getAttrOrDefault<std::string>(ci_tube, _Unicode(direction), "left");
0228           int coord_factor;
0229           if (direction == "left")
0230             coord_factor = 1;
0231           else if (direction == "right")
0232             coord_factor = -1;
0233           else
0234             throw std::runtime_error(
0235                 "BarrelTOF cooling tube direction can only be either left or right, not " +
0236                 direction + ".");
0237           std::string pipe_material =
0238               getAttrOrDefault<std::string>(ci_tube, _Unicode(pipe_material), "");
0239           std::string coolant_material =
0240               getAttrOrDefault<std::string>(ci_tube, _Unicode(coolant_material), "");
0241 
0242           // U-shape water pipes
0243           // The two sides of the "U"
0244           Tube pipe_in(pipe_min_r, pipe_max_r, (length / 2 + std::fabs(bend_y)) / 2);
0245           Volume pipe_in_vol(ci_tube.nameStr() + "_pipe1" + suffix, pipe_in,
0246                                  description.material(pipe_material));
0247           m_vol.placeVolume(pipe_in_vol,
0248                                 Transform3D(RotationZYX(0, 0, -M_PI / 2),
0249                                             Position(pos_x - bend_r + pipe_offset_x,
0250                                                      pos_y - coord_factor * (bend_y - length / 2) / 2,
0251                                                      pos_z + zoff)));
0252           SubtractionSolid c_sbox1(
0253               c_box, pipe_in,
0254               Transform3D(
0255                   RotationZYX(0, 0, -M_PI / 2),
0256                   Position(-bend_r + pipe_offset_x, coord_factor * (length / 2 - bend_y) / 2, 0)));
0257           // coolant inside the tube
0258           Tube coolant_in(0, pipe_min_r, (length / 2 + std::fabs(bend_y)) / 2);
0259           Volume coolant_in_vol(ci_tube.nameStr() + "_coolant1" + suffix, coolant_in,
0260                                     description.material(coolant_material));
0261           m_vol.placeVolume(coolant_in_vol,
0262                                 Transform3D(RotationZYX(0, 0, -M_PI / 2),
0263                                             Position(pos_x - bend_r + pipe_offset_x,
0264                                                      pos_y - coord_factor * (bend_y - length / 2) / 2,
0265                                                      pos_z + zoff)));
0266           SubtractionSolid c_sbox2(
0267               c_sbox1, coolant_in,
0268               Transform3D(
0269                   RotationZYX(0, 0, -M_PI / 2),
0270                   Position(-bend_r + pipe_offset_x, coord_factor * (length / 2 - bend_y) / 2, 0)));
0271 
0272           // other long side of the tube
0273           Tube pipe_out(pipe_min_r, pipe_max_r, (length / 2 + std::fabs(bend_y)) / 2);
0274           Volume pipe_out_vol(ci_tube.nameStr() + "_pipe2" + suffix, pipe_out,
0275                                   description.material(pipe_material));
0276           m_vol.placeVolume(pipe_out_vol,
0277                                 Transform3D(RotationZYX(0, 0, -M_PI / 2),
0278                                             Position(pos_x + bend_r + pipe_offset_x,
0279                                                      pos_y - coord_factor * (bend_y - length / 2) / 2,
0280                                                      pos_z + zoff)));
0281           SubtractionSolid c_sbox3(
0282               c_sbox2, pipe_out,
0283               Transform3D(
0284                   RotationZYX(0, 0, -M_PI / 2),
0285                   Position(bend_r + pipe_offset_x, coord_factor * (length / 2 - bend_y) / 2, 0)));
0286           // coolant inside the tube
0287           Tube coolant_out(0, pipe_min_r, (length / 2 + std::fabs(bend_y)) / 2);
0288           Volume coolant_out_vol(ci_tube.nameStr() + "_coolant2" + suffix, coolant_out,
0289                                      description.material(coolant_material));
0290           m_vol.placeVolume(coolant_out_vol,
0291                                 Transform3D(RotationZYX(0, 0, -M_PI / 2),
0292                                             Position(pos_x + bend_r + pipe_offset_x,
0293                                                      pos_y - coord_factor * (bend_y - length / 2) / 2,
0294                                                      pos_z + zoff)));
0295           SubtractionSolid c_sbox4(
0296               c_sbox3, coolant_out,
0297               Transform3D(
0298                   RotationZYX(0, 0, -M_PI / 2),
0299                   Position(bend_r + pipe_offset_x, coord_factor * (length / 2 - bend_y) / 2, 0)));
0300 
0301           // the U part of the U-shape
0302           Torus pipe_bend(bend_r, pipe_min_r, pipe_max_r + 0.001, direction == "left" ? M_PI : 0,
0303                               M_PI);
0304           Volume pipe_bend_vol(ci_tube.nameStr() + "_pipeU" + suffix, pipe_bend,
0305                                    description.material(pipe_material));
0306           m_vol.placeVolume(pipe_bend_vol,
0307                                 Transform3D(RotationZYX(0, 0, 0),
0308                                             Position(pos_x + pipe_offset_x,
0309                                                      pos_y - coord_factor * bend_y, pos_z + zoff)));
0310 
0311           // coolant
0312           Torus coolant_bend(bend_r, 0, pipe_min_r, direction == "left" ? M_PI : 0, M_PI);
0313           Volume coolant_bend_vol(ci_tube.nameStr() + "_coolantU" + suffix, coolant_bend,
0314                                       description.material(coolant_material));
0315           m_vol.placeVolume(coolant_bend_vol,
0316                                 Transform3D(RotationZYX(0, 0, 0),
0317                                             Position(pos_x + pipe_offset_x,
0318                                                      pos_y - coord_factor * bend_y, pos_z + zoff)));
0319 
0320           // carve out the U-bent from stave
0321           Torus coolant_bend_carveout(bend_r, 0, pipe_max_r, direction == "left" ? M_PI : 0, M_PI);
0322           SubtractionSolid c_sbox5(c_sbox4, coolant_bend_carveout,
0323                                        Transform3D(RotationZYX(0, 0, 0),
0324                                                    Position(pipe_offset_x, -coord_factor * bend_y, 0)));
0325 
0326           c_vol = Volume(c_nam, c_sbox5, description.material(x_comp.materialStr()));
0327         } else
0328           c_vol = Volume(c_nam, c_box, description.material(x_comp.materialStr()));
0329 
0330         Volume test;
0331         test = c_vol;
0332 
0333         // center if off by half the box length if box length is cut in half
0334         Position c_pos(pos_x, pos_y, pos_z + zoff);
0335         RotationZYX c_rot(rot_z, rot_y, rot_x);
0336         pv = m_vol.placeVolume(c_vol, Transform3D(c_rot, c_pos));
0337 
0338         c_vol.setRegion(description, x_comp.regionStr());
0339         c_vol.setLimitSet(description, x_comp.limitsStr());
0340         c_vol.setVisAttributes(description, x_comp.visStr());
0341         if (x_comp.isSensitive()) {
0342           pv.addPhysVolID("sensor", sensor_number++);
0343           pv.addPhysVolID("segmentation_id", segmentation_id);
0344           c_vol.setSensitiveDetector(sens);
0345           sensitives[m_nam].push_back(pv);
0346           module_thicknesses[m_nam] = {thickness_so_far + thickness / 2.0,
0347                                        total_thickness - thickness_so_far - thickness / 2.0};
0348 
0349           // -------- create a measurement plane for the tracking surface attched to the sensitive volume -----
0350           Vector3D u(-1., 0., 0.);
0351           Vector3D v(0., -1., 0.);
0352           Vector3D n(0., 0., 1.);
0353           //    Vector3D o( 0. , 0. , 0. ) ;
0354 
0355           // compute the inner and outer thicknesses that need to be assigned to the tracking surface
0356           // depending on wether the support is above or below the sensor
0357           double inner_thickness = module_thicknesses[m_nam][0];
0358           double outer_thickness = module_thicknesses[m_nam][1];
0359 
0360           SurfaceType type(SurfaceType::Sensitive);
0361 
0362           // if( isStripDetector )
0363           //  type.setProperty( SurfaceType::Measurement1D , true ) ;
0364 
0365           VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); //,o ) ;
0366           volplane_surfaces[m_nam].push_back(surf);
0367 
0368           //--------------------------------------------
0369         }
0370         if (z_stacking) {
0371           thickness_sum += thickness;
0372           thickness_so_far += thickness;
0373           // apply relative offsets in z-position used to stack components side-by-side
0374           thickness_sum += pos_z;
0375           thickness_so_far += pos_z;
0376         }
0377       };
0378 
0379       double pos_x = 0, pos_y = 0, pos_z = 0;
0380       double rot_x = 0, rot_y = 0, rot_z = 0;
0381       if (x_rot) {
0382         rot_x = x_rot.x(0);
0383         rot_y = x_rot.y(0);
0384         rot_z = x_rot.z(0);
0385       }
0386       if (x_pos) {
0387         pos_x = x_pos.x(0);
0388         pos_y = x_pos.y(0);
0389         pos_z = x_pos.z(0);
0390       }
0391       double width     = x_comp.width();
0392       double length    = x_comp.length();
0393       double thickness = x_comp.thickness();
0394       bool keep_layer  = getAttrOrDefault<bool>(x_comp, _Unicode(keep_layer), false);
0395 
0396       if (x_comp.hasChild(_Unicode(GridSensors))) {
0397         auto x_comp_t = x_comp.child(_Unicode(GridSensors));
0398         // x-distance between centers of neighboring sensors
0399         double sensors_xdist = getAttrOrDefault<double>(x_comp_t, _Unicode(xdist), x_comp.width());
0400         // y-distance between centers of neighboring sensors
0401         double sensors_ydist = getAttrOrDefault<double>(x_comp_t, _Unicode(ydist), x_comp.length());
0402         // number of rows of sensors in a stave
0403         int nsensors_x = getAttrOrDefault<int>(x_comp_t, _Unicode(nx), 1);
0404         // number of column of sensors in a stave
0405         int nsensors_y = getAttrOrDefault<int>(x_comp_t, _Unicode(ny), 1);
0406         // x-location of the center of the leftmost sensor
0407         double start_x = getAttrOrDefault<double>(x_comp_t, _Unicode(start_x), 0);
0408         // y-location of the center of the uppermost sensor
0409         double start_y = getAttrOrDefault<double>(x_comp_t, _Unicode(start_y), 0);
0410         // z-locatino of the center of all sensors (All sensors appears at the same z-layer
0411         double start_z = getAttrOrDefault<double>(x_comp_t, _Unicode(start_z), 0);
0412         // Illustration of variables
0413         //
0414         //               |<-------------sensors_ydist------------>|<-------------sensors_ydist------------>|
0415         //   |      <xcomp.length()>       |          |      <xcomp.length()>       |          |helf_sensor|
0416         //
0417         //   y-dist is the distance between centers of sensors
0418         //   each xcomp represent a column of cell
0419         //   half sensor has a width of 0.5*xcomp.length()
0420         //   In a half sensor, the sensor center is aligned with the edge, ensuring that `sensors_ydist` remains centered on a full sensor.
0421         //   Weather the half sensor is placed to the left or right of sensor_ydist depends on half_sensor_str below
0422         auto half_length_str =
0423             getAttrOrDefault<std::string>(x_comp_t, _Unicode(half_length), "none");
0424 
0425         double current_x = start_x;
0426         for (int nx = 0; nx < nsensors_x; ++nx) {
0427           double current_y = start_y;
0428           for (int ny = 0; ny < nsensors_y; ++ny) {
0429             double sensor_length     = length;
0430             double tmp_sensors_ydist = sensors_ydist;
0431             bool half_sensor         = false;
0432             // when we draw half a sensor, the center has to be shifted by 0.25 times the length of a sensor
0433             // distance between centers to the next sensor also has to be reduced by 0.25 times the length of a sensor
0434             if ((half_length_str == "left" || half_length_str == "both") && ny == 0) {
0435               sensor_length = 0.5 * length;
0436               current_y += 0.25 * length;
0437               tmp_sensors_ydist -= 0.25 * length;
0438               half_sensor = true;
0439             }
0440             // same idea, but when you are drawing to the right, the right sensor center has to move in -y direction
0441             if ((half_length_str == "right" || half_length_str == "both") && ny == nsensors_y - 1) {
0442               sensor_length = 0.5 * length;
0443               current_y -= 0.25 * length;
0444               tmp_sensors_ydist += 0.5 * length;
0445               half_sensor = true;
0446             }
0447 
0448             bool last_sensor_in_stave = ((nx == nsensors_x - 1) && (ny == nsensors_y - 1));
0449             bool segmentation_id =
0450                 half_sensor ? 1 : 0; // keys to distinguish segmentation class for half sensor
0451                                      //
0452             make_box(
0453                 width, sensor_length, thickness, current_x, current_y, start_z, rot_x, rot_y, rot_z,
0454                 last_sensor_in_stave && !keep_layer, segmentation_id,
0455                 "_ix" + std::to_string(nx) + "_iy" +
0456                     std::to_string(
0457                         ny)); // all sensors are located at the same z-layer, keep the same sensor number for all columns in the same sensor
0458             // increment z-layers only at the end, after the last sensor is added
0459             // return current_y to the center of the sensor
0460             current_y += tmp_sensors_ydist;
0461           }
0462           current_x += sensors_xdist;
0463         }
0464       } else
0465         make_box(width, length, thickness, pos_x, pos_y, pos_z, rot_x, rot_y, rot_z, !keep_layer);
0466     }
0467   }
0468 
0469   // now build the layers
0470   for (xml_coll_t li(x_det, _U(layer)); li; ++li) {
0471     xml_comp_t x_layer  = li;
0472     xml_comp_t x_barrel = x_layer.child(_U(barrel_envelope));
0473     xml_comp_t x_layout = x_layer.child(_U(rphi_layout));
0474     xml_comp_t z_layout = x_layer.child(_U(z_layout)); // Get the <z_layout> element.
0475     int lay_id          = x_layer.id();
0476     string m_nam        = x_layer.moduleStr();
0477     string lay_nam      = det_name + _toString(x_layer.id(), "_layer%d");
0478     Tube lay_tub(x_barrel.inner_r(), x_barrel.outer_r(), x_barrel.z_length() / 2.0);
0479     Volume lay_vol(lay_nam, lay_tub, air); // Create the layer envelope volume.
0480     Position lay_pos(0, 0, getAttrOrDefault(x_barrel, _U(z0), 0.));
0481     lay_vol.setVisAttributes(description.visAttributes(x_layer.visStr()));
0482 
0483     double phi0     = x_layout.phi0();     // Starting phi of first module.
0484     double phi_tilt = x_layout.phi_tilt(); // Phi tilt of a module.
0485     double rc       = x_layout.rc();       // Radius of the module center.
0486     int nphi        = x_layout.nphi();     // Number of modules in phi.
0487     double rphi_dr  = x_layout.dr();       // The delta radius of every other module.
0488     double phi_incr = (M_PI * 2) / nphi;   // Phi increment for one module.
0489     double phic     = phi0;                // Phi of the module center.
0490     double z0       = z_layout.z0();       // Z position of first module in phi.
0491     double nz       = z_layout.nz();       // Number of modules to place in z.
0492     double z_dr     = z_layout.dr();       // Radial displacement parameter, of every other module.
0493 
0494     Volume module_env = volumes[m_nam];
0495     DetElement lay_elt(sdet, lay_nam, lay_id);
0496     Placements& sensVols = sensitives[m_nam];
0497 
0498     // the local coordinate systems of modules in dd4hep and acts differ
0499     // see http://acts.web.cern.ch/ACTS/latest/doc/group__DD4hepPlugins.html
0500     auto& layerParams =
0501         DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(lay_elt);
0502 
0503     for (xml_coll_t lmat(x_layer, _Unicode(layer_material)); lmat; ++lmat) {
0504       xml_comp_t x_layer_material = lmat;
0505       DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_layer_material, layerParams,
0506                                                       "layer_material");
0507     }
0508 
0509     // Z increment for module placement along Z axis.
0510     // Adjust for z0 at center of module rather than
0511     // the end of cylindrical envelope.
0512     double z_incr = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0;
0513     // Starting z for module placement along Z axis.
0514     double module_z = -z0;
0515     int module      = 1;
0516 
0517     // Loop over the number of modules in phi.
0518     for (int ii = 0; ii < nphi; ii++) {
0519       double dx = z_dr * std::cos(phic + phi_tilt); // Delta x of module position.
0520       double dy = z_dr * std::sin(phic + phi_tilt); // Delta y of module position.
0521       double x  = rc * std::cos(phic);              // Basic x module position.
0522       double y  = rc * std::sin(phic);              // Basic y module position.
0523 
0524       // Loop over the number of modules in z.
0525       for (int j = 0; j < nz; j++) {
0526         string module_name = _toString(module, "module%d");
0527         DetElement mod_elt(lay_elt, module_name, module);
0528 
0529         Transform3D tr(RotationZYX(0, ((M_PI / 2) - phic - phi_tilt), -M_PI / 2),
0530                        Position(x, y, module_z));
0531 
0532         pv = lay_vol.placeVolume(module_env, tr);
0533         pv.addPhysVolID("module", module);
0534         mod_elt.setPlacement(pv);
0535         for (size_t ic = 0; ic < sensVols.size(); ++ic) {
0536           PlacedVolume sens_pv = sensVols[ic];
0537           DetElement comp_de(mod_elt, std::string("de_") + sens_pv.volume().name(), module);
0538           comp_de.setPlacement(sens_pv);
0539 
0540           auto& comp_de_params =
0541               DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(comp_de);
0542           comp_de_params.set<string>("axis_definitions", "XYZ");
0543           // comp_de.setAttributes(description, sens_pv.volume(), x_layer.regionStr(), x_layer.limitsStr(),
0544           //                       xml_det_t(xmleles[m_nam]).visStr());
0545           //
0546 
0547           volSurfaceList(comp_de)->push_back(volplane_surfaces[m_nam][ic]);
0548         }
0549 
0550         /// Increase counters etc.
0551         module++;
0552         // Adjust the x and y coordinates of the module.
0553         x += dx;
0554         y += dy;
0555         // Flip sign of x and y adjustments.
0556         dx *= -1;
0557         dy *= -1;
0558         // Add z increment to get next z placement pos.
0559         module_z += z_incr;
0560       }
0561       phic += phi_incr; // Increment the phi placement of module.
0562       rc += rphi_dr;    // Increment the center radius according to dr parameter.
0563       rphi_dr *= -1;    // Flip sign of dr parameter.
0564       module_z = -z0;   // Reset the Z placement parameter for module.
0565     }
0566     // Create the PhysicalVolume for the layer.
0567     pv = assembly.placeVolume(lay_vol, lay_pos); // Place layer in mother
0568     pv.addPhysVolID("layer", lay_id);            // Set the layer ID.
0569     lay_elt.setAttributes(description, lay_vol, x_layer.regionStr(), x_layer.limitsStr(),
0570                           x_layer.visStr());
0571     lay_elt.setPlacement(pv);
0572   }
0573   sdet.setAttributes(description, assembly, x_det.regionStr(), x_det.limitsStr(), x_det.visStr());
0574   assembly.setVisAttributes(description.invisible());
0575   pv = description.pickMotherVolume(sdet).placeVolume(assembly);
0576   pv.addPhysVolID("system", det_id); // Set the subdetector system ID.
0577   sdet.setPlacement(pv);
0578   return sdet;
0579 }
0580 
0581 //@}
0582 // clang-format off
0583 DECLARE_DETELEMENT(epic_TOFBarrel,       create_TOFBarrel)