Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:15:53

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2022 Whitney Armstrong, Sylvester Joosten
0003 
0004 /** \addtogroup PID
0005  * \brief Type: **Barrel bar detector (think DIRC) with longitudinal frame**.
0006  * \author S. Joosten
0007  *
0008  * \ingroup PID
0009  *
0010  *
0011  * \code
0012  * \endcode
0013  *
0014  * @{
0015  */
0016 #include "DD4hep/DetFactoryHelper.h"
0017 #include "DD4hep/Printout.h"
0018 #include "DD4hep/Shapes.h"
0019 #include "DDRec/DetectorData.h"
0020 #include "DDRec/Surface.h"
0021 #include "XML/Layering.h"
0022 #include <array>
0023 
0024 using namespace std;
0025 using namespace dd4hep;
0026 
0027 /** Barrel Bar detector with optional framek
0028  *
0029  * - Optional "frame" tag within the module element (frame eats part of the module width
0030  *   and is longitudinal at both sides)
0031  * - Detector is setup as a "tracker" so we can use the hits to perform fast MC
0032  *   for e.g. the DIRC
0033  *
0034  */
0035 static Ref_t create_BarrelBarDetectorWithSideFrame(Detector& description, xml_h e,
0036                                                    SensitiveDetector sens) {
0037   typedef vector<PlacedVolume> Placements;
0038   xml_det_t x_det = e;
0039   Material air    = description.air();
0040   int det_id      = x_det.id();
0041   string det_name = x_det.nameStr();
0042   DetElement sdet(det_name, det_id);
0043   map<string, Volume> volumes;
0044   map<string, Placements> sensitives;
0045   map<string, std::vector<rec::VolPlane>> volplane_surfaces;
0046   PlacedVolume pv;
0047   dd4hep::xml::Dimension dimensions(x_det.dimensions());
0048   xml_dim_t dirc_pos = x_det.position();
0049 
0050   map<string, std::array<double, 2>> module_thicknesses;
0051 
0052   Tube topVolumeShape(dimensions.rmin(), dimensions.rmax(), dimensions.length() * 0.5);
0053   Volume assembly(det_name, topVolumeShape, air);
0054 
0055   sens.setType("tracker");
0056 
0057   // loop over the modules
0058   for (xml_coll_t mi(x_det, _U(module)); mi; ++mi) {
0059     xml_comp_t x_mod = mi;
0060     string m_nam     = x_mod.nameStr();
0061 
0062     if (volumes.find(m_nam) != volumes.end()) {
0063       printout(ERROR, "BarrelBarDetectorWithSideFrame",
0064                string((string("Module with named ") + m_nam + string(" already exists."))).c_str());
0065       throw runtime_error("Logics error in building modules.");
0066     }
0067 
0068     int ncomponents        = 0;
0069     double total_thickness = 0;
0070 
0071     // Compute module total thickness from components
0072     xml_coll_t ci(x_mod, _U(module_component));
0073     for (ci.reset(), total_thickness = 0.0; ci; ++ci) {
0074       total_thickness += xml_comp_t(ci).thickness();
0075     }
0076     // the module assembly volume
0077     Assembly m_vol(m_nam);
0078     volumes[m_nam] = m_vol;
0079     m_vol.setVisAttributes(description, x_mod.visStr());
0080 
0081     // Optional module frame.
0082     // frame is 2 longitudinal bars at the side of the module
0083     //
0084     // |___| <-- example module cross section (x-y plane), frame is flush with the
0085     //           bottom of the module and protrudes on the top if needed
0086     //
0087 
0088     // Get frame width, as it impacts the main module for being built. We
0089     // construct the actual frame structure later (once we know the module width)
0090     double frame_width = 0;
0091     if (x_mod.hasChild(_U(frame))) {
0092       xml_comp_t m_frame = x_mod.child(_U(frame));
0093       frame_width        = m_frame.width();
0094     }
0095 
0096     double thickness_so_far    = 0.0;
0097     double thickness_sum       = -total_thickness / 2.0;
0098     double max_component_width = 0;
0099     for (xml_coll_t mci(x_mod, _U(module_component)); mci; ++mci, ++ncomponents) {
0100       xml_comp_t x_comp = mci;
0101       string c_nam      = _toString(ncomponents, "component%d");
0102 
0103       double box_width    = x_comp.width() - 2 * frame_width;
0104       max_component_width = fmax(max_component_width, box_width);
0105 
0106       Box c_box{box_width / 2, x_comp.length() / 2, x_comp.thickness() / 2};
0107       Volume c_vol{c_nam, c_box, description.material(x_comp.materialStr())};
0108 
0109       pv = m_vol.placeVolume(c_vol, Position(0, 0, thickness_sum + x_comp.thickness() / 2.0));
0110 
0111       c_vol.setRegion(description, x_comp.regionStr());
0112       c_vol.setLimitSet(description, x_comp.limitsStr());
0113       c_vol.setVisAttributes(description, x_comp.visStr());
0114       if (x_comp.isSensitive()) {
0115         c_vol.setSensitiveDetector(sens);
0116         sensitives[m_nam].push_back(pv);
0117         module_thicknesses[m_nam] = {thickness_so_far + x_comp.thickness() / 2.0,
0118                                      total_thickness - thickness_so_far - x_comp.thickness() / 2.0};
0119         // -------- create a measurement plane for the tracking surface attched to the sensitive volume -----
0120         rec::Vector3D u(0., 1., 0.);
0121         rec::Vector3D v(0., 0., 1.);
0122         rec::Vector3D n(1., 0., 0.);
0123 
0124         // compute the inner and outer thicknesses that need to be assigned to the tracking surface
0125         // depending on wether the support is above or below the sensor
0126         double inner_thickness = module_thicknesses[m_nam][0];
0127         double outer_thickness = module_thicknesses[m_nam][1];
0128 
0129         rec::SurfaceType type(rec::SurfaceType::Sensitive);
0130 
0131         rec::VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n); //,o ) ;
0132         volplane_surfaces[m_nam].push_back(surf);
0133       }
0134       thickness_sum += x_comp.thickness();
0135       thickness_so_far += x_comp.thickness();
0136     }
0137     // Now add-on the frame
0138     if (x_mod.hasChild(_U(frame))) {
0139       xml_comp_t m_frame     = x_mod.child(_U(frame));
0140       double frame_thickness = getAttrOrDefault<double>(m_frame, _U(thickness), total_thickness);
0141 
0142       Box lframe_box{m_frame.width() / 2., m_frame.length() / 2., frame_thickness / 2.};
0143       Box rframe_box{m_frame.width() / 2., m_frame.length() / 2., frame_thickness / 2.};
0144 
0145       // Keep track of frame with so we can adjust the module bars appropriately
0146 
0147       Volume lframe_vol{"left_frame", lframe_box, description.material(m_frame.materialStr())};
0148       Volume rframe_vol{"right_frame", rframe_box, description.material(m_frame.materialStr())};
0149       lframe_vol.setVisAttributes(description, m_frame.visStr());
0150       rframe_vol.setVisAttributes(description, m_frame.visStr());
0151 
0152       m_vol.placeVolume(lframe_vol, Position(frame_width / 2. + max_component_width / 2, 0.,
0153                                              frame_thickness / 2. - total_thickness / 2.0));
0154       m_vol.placeVolume(rframe_vol, Position(-frame_width / 2. - max_component_width / 2, 0.,
0155                                              frame_thickness / 2. - total_thickness / 2.0));
0156     }
0157   }
0158 
0159   // now build the layers
0160   for (xml_coll_t li(x_det, _U(layer)); li; ++li) {
0161     xml_comp_t x_layer  = li;
0162     xml_comp_t x_barrel = x_layer.child(_U(barrel_envelope));
0163     xml_comp_t x_layout = x_layer.child(_U(rphi_layout));
0164     xml_comp_t z_layout = x_layer.child(_U(z_layout)); // Get the <z_layout> element.
0165     int lay_id          = x_layer.id();
0166     string m_nam        = x_layer.moduleStr();
0167     string lay_nam      = _toString(x_layer.id(), "layer%d");
0168     Tube lay_tub(x_barrel.inner_r(), x_barrel.outer_r(), x_barrel.z_length() / 2.0);
0169     Volume lay_vol(lay_nam, lay_tub, air); // Create the layer envelope volume.
0170     lay_vol.setVisAttributes(description, x_layer.visStr());
0171 
0172     double phi0     = x_layout.phi0();     // Starting phi of first module.
0173     double phi_tilt = x_layout.phi_tilt(); // Phi tilt of a module.
0174     double rc       = x_layout.rc();       // Radius of the module center.
0175     int nphi        = x_layout.nphi();     // Number of modules in phi.
0176     double rphi_dr  = x_layout.dr();       // The delta radius of every other module.
0177     double phi_incr = (M_PI * 2) / nphi;   // Phi increment for one module.
0178     double phic     = phi0;                // Phi of the module center.
0179     double z0       = z_layout.z0();       // Z position of first module in phi.
0180     double nz       = z_layout.nz();       // Number of modules to place in z.
0181     double z_dr     = z_layout.dr();       // Radial displacement parameter, of every other module.
0182 
0183     Volume module_env = volumes[m_nam];
0184     DetElement lay_elt(sdet, _toString(x_layer.id(), "layer%d"), lay_id);
0185     Placements& sensVols = sensitives[m_nam];
0186 
0187     // Z increment for module placement along Z axis.
0188     // Adjust for z0 at center of module rather than
0189     // the end of cylindrical envelope.
0190     double z_incr = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0;
0191     // Starting z for module placement along Z axis.
0192     double module_z = -z0;
0193     int module      = 1;
0194 
0195     // Loop over the number of modules in phi.
0196     for (int ii = 0; ii < nphi; ii++) {
0197       double dx = z_dr * std::cos(phic + phi_tilt); // Delta x of module position.
0198       double dy = z_dr * std::sin(phic + phi_tilt); // Delta y of module position.
0199       double x  = rc * std::cos(phic);              // Basic x module position.
0200       double y  = rc * std::sin(phic);              // Basic y module position.
0201 
0202       // Loop over the number of modules in z.
0203       for (int j = 0; j < nz; j++) {
0204         string module_name = _toString(module, "module%d");
0205         DetElement mod_elt(lay_elt, module_name, module);
0206 
0207         Transform3D tr(RotationZYX(0, ((M_PI / 2) - phic - phi_tilt), -M_PI / 2),
0208                        Position(x, y, module_z));
0209 
0210         pv = lay_vol.placeVolume(module_env, tr);
0211         pv.addPhysVolID("module", module);
0212         pv.addPhysVolID("section", j);
0213         mod_elt.setPlacement(pv);
0214         for (size_t ic = 0; ic < sensVols.size(); ++ic) {
0215           PlacedVolume sens_pv = sensVols[ic];
0216           DetElement comp_de(mod_elt, std::string("de_") + sens_pv.volume().name(), module);
0217           comp_de.setPlacement(sens_pv);
0218           rec::volSurfaceList(comp_de)->push_back(volplane_surfaces[m_nam][ic]);
0219         }
0220 
0221         /// Increase counters etc.
0222         module++;
0223         // Adjust the x and y coordinates of the module.
0224         x += dx;
0225         y += dy;
0226         // Flip sign of x and y adjustments.
0227         dx *= -1;
0228         dy *= -1;
0229         // Add z increment to get next z placement pos.
0230         module_z += z_incr;
0231       }
0232       phic += phi_incr; // Increment the phi placement of module.
0233       rc += rphi_dr;    // Increment the center radius according to dr parameter.
0234       rphi_dr *= -1;    // Flip sign of dr parameter.
0235       module_z = -z0;   // Reset the Z placement parameter for module.
0236     }
0237     // Create the PhysicalVolume for the layer.
0238     pv = assembly.placeVolume(lay_vol); // Place layer in mother
0239     pv.addPhysVolID("layer", lay_id);   // Set the layer ID.
0240     lay_elt.setAttributes(description, lay_vol, x_layer.regionStr(), x_layer.limitsStr(),
0241                           x_layer.visStr());
0242     lay_elt.setPlacement(pv);
0243   }
0244   sdet.setAttributes(description, assembly, x_det.regionStr(), x_det.limitsStr(), x_det.visStr());
0245   assembly.setVisAttributes(description.invisible());
0246   pv = description.pickMotherVolume(sdet).placeVolume(assembly, Position(0, 0, dirc_pos.z()));
0247   pv.addPhysVolID("system", det_id); // Set the subdetector system ID.
0248   sdet.setPlacement(pv);
0249   return sdet;
0250 }
0251 
0252 //@}
0253 // clang-format off
0254 DECLARE_DETELEMENT(epic_BarrelBarDetectorWithSideFrame, create_BarrelBarDetectorWithSideFrame)
0255 DECLARE_DETELEMENT(epic_FakeDIRC, create_BarrelBarDetectorWithSideFrame)