Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-06-17 07:06:54

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2022 Nicolas Schmidt
0003 
0004 /** \addtogroup Trackers Trackers
0005  * \brief Type: **Endcap Tracker with TOF**.
0006  * \author N. Schmidt
0007  *
0008  * \ingroup trackers
0009  *
0010  * @{
0011  */
0012 #include "DD4hep/DetFactoryHelper.h"
0013 #include "DD4hep/Printout.h"
0014 #include "DD4hep/Shapes.h"
0015 #include "DD4hepDetectorHelper.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 <map>
0022 
0023 using namespace std;
0024 using namespace dd4hep;
0025 using namespace dd4hep::rec;
0026 using namespace dd4hep::detail;
0027 
0028 static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens) {
0029   xml_det_t x_det      = e;
0030   int det_id           = x_det.id();
0031   std::string det_name = x_det.nameStr();
0032   DetElement sdet(det_name, det_id);
0033   Material air    = description.material("Air");
0034   Material carbon = description.material("CarbonFiber");
0035   PlacedVolume pv;
0036 
0037   map<string, std::array<double, 2>> module_thicknesses;
0038 
0039   // Set detector type flag
0040   dd4hep::xml::setDetectorTypeFlag(x_det, sdet);
0041   auto& params = DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(sdet);
0042   // Add the volume boundary material if configured
0043   for (xml_coll_t bmat(x_det, _Unicode(boundary_material)); bmat; ++bmat) {
0044     xml_comp_t x_boundary_material = bmat;
0045     DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_boundary_material, params,
0046                                                     "boundary_material");
0047   }
0048 
0049   Assembly assembly(det_name);
0050   assembly.setVisAttributes(description.invisible());
0051   sens.setType("tracker");
0052 
0053   float zPos = 0;
0054   // now build the envelope for the detector
0055   xml_comp_t x_layer  = x_det.child(_Unicode(layer));
0056   xml_comp_t envelope = x_layer.child(_Unicode(envelope), false);
0057   int lay_id          = x_layer.id();
0058   string l_nam        = x_layer.moduleStr();
0059   string lay_nam      = det_name + _toString(x_layer.id(), "_layer%d");
0060   Tube lay_tub(envelope.rmin(), envelope.rmax(), envelope.length() / 2.0);
0061   Volume lay_vol(lay_nam, lay_tub, air); // Create the layer envelope volume.
0062   zPos = envelope.zstart();
0063   Position lay_pos(0, 0, 0);
0064   lay_vol.setVisAttributes(description.visAttributes(x_layer.visStr()));
0065 
0066   DetElement lay_elt(sdet, lay_nam, lay_id);
0067 
0068   // the local coordinate systems of modules in dd4hep and acts differ
0069   // see http://acts.web.cern.ch/ACTS/latest/doc/group__DD4hepPlugins.html
0070   auto& layerParams =
0071       DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(lay_elt);
0072 
0073   for (xml_coll_t lmat(x_layer, _Unicode(layer_material)); lmat; ++lmat) {
0074     xml_comp_t x_layer_material = lmat;
0075     DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_layer_material, layerParams,
0076                                                     "layer_material");
0077   }
0078 
0079   // dimensions of the modules (2x2 sensors)
0080   xml_comp_t x_modsz = x_det.child(_Unicode(modsize));
0081 
0082   double module_x       = x_modsz.length();
0083   double module_y       = x_modsz.width();
0084   double module_overlap = getAttrOrDefault(x_modsz, _Unicode(overlap), 0.); // x_modsz.overlap();
0085   double module_spacing = getAttrOrDefault(x_modsz, _Unicode(spacing), 0.); // x_modsz.overlap();
0086 
0087   //! Add support structure
0088   xml_comp_t x_supp          = x_det.child(_Unicode(support));
0089   xml_comp_t x_supp_envelope = x_supp.child(_Unicode(envelope), false);
0090 
0091   double total_thickness = 0;
0092   xml_comp_t x_modFront  = x_det.child(_Unicode(moduleFront));
0093   xml_comp_t x_modBack   = x_det.child(_Unicode(moduleBack));
0094 
0095   // Compute module total thickness from components
0096   xml_coll_t ci(x_modFront, _U(module_component));
0097   for (ci.reset(), total_thickness = 0.0; ci; ++ci) {
0098     total_thickness += xml_comp_t(ci).thickness();
0099   }
0100 
0101   int module = 0;
0102   int nx     = 25;
0103   int ny     = 15;
0104   for (int ix = 0; ix < 2 * nx; ix++) {
0105     float xcoord = (ix - nx) * (module_x + module_spacing);
0106     for (int iy = 0; iy < 2 * ny; iy++) {
0107       float ycoord = (iy - ny) * (module_y - module_overlap);
0108       //! Note the module ordering is different for front and back side
0109       xml_comp_t x_modCurr = iy % 2 == 0 ? x_modFront : x_modBack;
0110 
0111       double module_z = x_supp_envelope.length() / 2.0 + total_thickness / 2;
0112       if (iy % 2 == 0) {
0113         module_z *= -1;
0114       }
0115       float corner_x1 = xcoord + module_x / 2;
0116       float corner_x2 = xcoord - module_x / 2;
0117       float corner_y1 = ycoord + module_y / 2;
0118       float corner_y2 = ycoord - module_y / 2;
0119       float maxRadius =
0120           std::max(std::max(std::hypot(corner_x1, corner_y1), std::hypot(corner_x2, corner_y2)),
0121                    std::max(std::hypot(corner_x1, corner_y2), std::hypot(corner_x2, corner_y1)));
0122       float minRadius =
0123           std::min(std::min(std::hypot(corner_x1, corner_y1), std::hypot(corner_x2, corner_y2)),
0124                    std::min(std::hypot(corner_x1, corner_y2), std::hypot(corner_x2, corner_y1)));
0125       if (maxRadius > envelope.rmax() || minRadius < envelope.rmin()) {
0126         continue;
0127       }
0128 
0129       string module_name = Form("module%d_%d_%d", module, ix, iy);
0130       DetElement mod_elt(lay_elt, module_name, module);
0131 
0132       // create individual sensor layers here
0133       string m_nam = Form("EndcapTOF_Module1_%d_%d", ix, iy);
0134 
0135       int ncomponents = 0;
0136       // the module assembly volume
0137       Assembly m_vol(m_nam);
0138       m_vol.setVisAttributes(description.visAttributes(x_modCurr.visStr()));
0139 
0140       double thickness_so_far     = 0.0;
0141       double thickness_sum        = -total_thickness / 2.0;
0142       double thickness_carbonsupp = 0.0;
0143       for (xml_coll_t mci(x_modCurr, _U(module_component)); mci; ++mci, ++ncomponents) {
0144         xml_comp_t x_comp  = mci;
0145         xml_comp_t x_pos   = x_comp.position(false);
0146         xml_comp_t x_rot   = x_comp.rotation(false);
0147         const string c_nam = Form("component_%d_%d", ix, iy);
0148         Box c_box(x_comp.width() / 2, x_comp.length() / 2, x_comp.thickness() / 2);
0149         Volume c_vol(c_nam, c_box, description.material(x_comp.materialStr()));
0150         if (x_comp.materialStr() == "CarbonFiber") {
0151           thickness_carbonsupp = x_comp.thickness();
0152         }
0153         // Utility variable for the relative z-offset based off the previous components
0154         const double zoff = thickness_sum + x_comp.thickness() / 2.0;
0155         if (x_pos && x_rot) {
0156           Position c_pos(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff);
0157           RotationZYX c_rot(x_rot.z(0), x_rot.y(0), x_rot.x(0));
0158           pv = m_vol.placeVolume(c_vol, Transform3D(c_rot, c_pos));
0159         } else if (x_rot) {
0160           Position c_pos(0, 0, zoff);
0161           pv = m_vol.placeVolume(
0162               c_vol, Transform3D(RotationZYX(x_rot.z(0), x_rot.y(0), x_rot.x(0)), c_pos));
0163         } else if (x_pos) {
0164           pv = m_vol.placeVolume(c_vol, Position(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff));
0165         } else {
0166           pv = m_vol.placeVolume(c_vol, Position(0, 0, zoff));
0167         }
0168         c_vol.setRegion(description, x_comp.regionStr());
0169         c_vol.setLimitSet(description, x_comp.limitsStr());
0170         c_vol.setVisAttributes(description, x_comp.visStr());
0171         if (x_comp.isSensitive()) {
0172           pv.addPhysVolID("idx", ix);
0173           pv.addPhysVolID("idy", iy);
0174           c_vol.setSensitiveDetector(sens);
0175           module_thicknesses[m_nam] = {thickness_so_far + x_comp.thickness() / 2.0,
0176                                        total_thickness - thickness_so_far -
0177                                            x_comp.thickness() / 2.0};
0178 
0179           // -------- create a measurement plane for the tracking surface attched to the sensitive volume -----
0180           Vector3D u(-1., 0., 0.);
0181           Vector3D v(0., -1., 0.);
0182           Vector3D n(0., 0., 1.);
0183 
0184           // compute the inner and outer thicknesses that need to be assigned to the tracking surface
0185           // depending on wether the support is above or below the sensor
0186           double inner_thickness = module_thicknesses[m_nam][0];
0187           double outer_thickness = module_thicknesses[m_nam][1];
0188 
0189           SurfaceType type(SurfaceType::Sensitive);
0190 
0191           VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n);
0192 
0193           DetElement comp_de(mod_elt, std::string("de_") + pv.volume().name(), module);
0194           comp_de.setPlacement(pv);
0195 
0196           auto& comp_de_params =
0197               DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(comp_de);
0198           comp_de_params.set<string>("axis_definitions", "XYZ");
0199           volSurfaceList(comp_de)->push_back(surf);
0200 
0201           //--------------------------------------------
0202         }
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       }
0211 
0212       const string suppb_nam =
0213           Form("suppbar_%d_%d", ix, iy); //_toString(ncomponents, "component%d");
0214       Box suppb_box((module_x + module_spacing) / 2, thickness_carbonsupp / 2,
0215                     x_supp_envelope.length() / 2);
0216       Volume suppb_vol(suppb_nam, suppb_box, carbon);
0217       Transform3D trsupp(RotationZYX(0, 0, 0),
0218                          Position(xcoord, ycoord + module_y / 2 - module_overlap / 2, 0));
0219       suppb_vol.setVisAttributes(description, "AnlGray");
0220 
0221       pv = lay_vol.placeVolume(suppb_vol, trsupp);
0222       // module built!
0223 
0224       Transform3D tr(RotationZYX(M_PI / 2, 0, 0), Position(xcoord, ycoord, module_z));
0225 
0226       pv = lay_vol.placeVolume(m_vol, tr);
0227       pv.addPhysVolID("module", module);
0228       mod_elt.setPlacement(pv);
0229     }
0230   }
0231 
0232   // Create the PhysicalVolume for the layer.
0233   pv = assembly.placeVolume(lay_vol, lay_pos); // Place layer in mother
0234   pv.addPhysVolID("layer", lay_id);            // Set the layer ID.
0235   lay_elt.setAttributes(description, lay_vol, x_layer.regionStr(), x_layer.limitsStr(),
0236                         x_layer.visStr());
0237   lay_elt.setPlacement(pv);
0238 
0239   pv = description.pickMotherVolume(sdet).placeVolume(assembly, Position(0, 0, zPos));
0240   pv.addPhysVolID("system", det_id);
0241   sdet.setPlacement(pv);
0242 
0243   return sdet;
0244 }
0245 
0246 //@}
0247 // clang-format off
0248 DECLARE_DETELEMENT(epic_TOFEndcap, create_detector)