File indexing completed on 2025-07-02 07:54:56
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include "DD4hep/DetFactoryHelper.h"
0012 #include "DD4hep/Printout.h"
0013 #include "DD4hep/Shapes.h"
0014 #include "DD4hepDetectorHelper.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 <map>
0021 #include <unordered_set>
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
0040 dd4hep::xml::setDetectorTypeFlag(x_det, sdet);
0041 auto& params = DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(sdet);
0042
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
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);
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
0069
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
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.);
0085 double module_spacing = getAttrOrDefault(x_modsz, _Unicode(spacing), 0.);
0086 double board_gap = getAttrOrDefault(x_modsz, _Unicode(board_gap), 0.);
0087
0088
0089 xml_comp_t x_supp = x_det.child(_Unicode(support));
0090 xml_comp_t x_supp_envelope = x_supp.child(_Unicode(envelope), false);
0091
0092 xml_comp_t x_modFrontLeft = x_det.child(_Unicode(moduleFrontLeft));
0093 xml_comp_t x_modFrontRight = x_det.child(_Unicode(moduleFrontRight));
0094 xml_comp_t x_modBackLeft = x_det.child(_Unicode(moduleBackLeft));
0095 xml_comp_t x_modBackRight = x_det.child(_Unicode(moduleBackRight));
0096
0097 xml_comp_t x_sensor_layout_front_left = x_det.child(_Unicode(sensor_layout_front_left));
0098 xml_comp_t x_sensor_layout_back_left = x_det.child(_Unicode(sensor_layout_back_left));
0099 xml_comp_t x_sensor_layout_front_right = x_det.child(_Unicode(sensor_layout_front_right));
0100 xml_comp_t x_sensor_layout_back_right = x_det.child(_Unicode(sensor_layout_back_right));
0101
0102 for (bool left : std::vector<bool>{true, false}) {
0103 for (bool front : std::vector<bool>{true, false}) {
0104 int module = (front << 1) + left;
0105 const std::string locStr =
0106 std::string(left ? "Left" : "Right") + std::string(front ? "Front" : "Back");
0107 float ycoord = envelope.rmax() -
0108 module_y / 2.;
0109 int iy = 0;
0110 xml_comp_t x_sensor_layout = x_sensor_layout_front_left;
0111 xml_comp_t x_modCurr = x_modFrontLeft;
0112
0113 if (front) {
0114 if (left) {
0115 x_sensor_layout = x_sensor_layout_front_left;
0116 x_modCurr = x_modFrontLeft;
0117 } else {
0118 x_sensor_layout = x_sensor_layout_front_right;
0119 x_modCurr = x_modFrontRight;
0120 }
0121 } else {
0122 if (left) {
0123 x_sensor_layout = x_sensor_layout_back_left;
0124 x_modCurr = x_modBackLeft;
0125 } else {
0126 x_sensor_layout = x_sensor_layout_back_right;
0127 x_modCurr = x_modBackRight;
0128 }
0129 }
0130
0131 double total_thickness = 0;
0132
0133 xml_coll_t ci(x_modCurr, _U(module_component));
0134
0135 for (ci.reset(), total_thickness = 0.0; ci; ++ci) {
0136 xml_comp_t x_comp = ci;
0137 bool keep_same_layer = getAttrOrDefault<bool>(x_comp, _Unicode(keep_layer), false);
0138 if (!keep_same_layer)
0139 total_thickness += x_comp.thickness();
0140 }
0141
0142 for (xml_coll_t lrow(x_sensor_layout, _Unicode(row)); lrow; ++lrow) {
0143 xml_comp_t x_row = lrow;
0144 double deadspace = getAttrOrDefault<double>(x_row, _Unicode(deadspace), 0);
0145 if (deadspace > 0) {
0146 ycoord -= deadspace;
0147 continue;
0148 }
0149 double x_offset = getAttrOrDefault<double>(x_row, _Unicode(x_offset), 0);
0150 int nsensors = getAttrOrDefault<int>(x_row, _Unicode(nsensors), 0);
0151
0152
0153
0154 std::unordered_set<int> sensors_id_board_edge;
0155 int curr_ix = nsensors;
0156 for (xml_coll_t lboard(x_row, _Unicode(board)); lboard; ++lboard) {
0157 xml_comp_t x_board = lboard;
0158 int nboard_sensors = getAttrOrDefault<int>(x_board, _Unicode(nsensors), 1);
0159 curr_ix += nboard_sensors;
0160 sensors_id_board_edge.insert(curr_ix);
0161 sensors_id_board_edge.insert(2 * nsensors - curr_ix -
0162 1);
0163 }
0164
0165 double accum_xoffset = x_offset;
0166 for (int ix = (left ? nsensors - 1 : nsensors); (ix >= 0) && (ix < 2 * nsensors);
0167 ix = ix + (left ? -1 : 1)) {
0168
0169 if (sensors_id_board_edge.find(ix) != sensors_id_board_edge.end())
0170 accum_xoffset = accum_xoffset + board_gap;
0171
0172
0173 float xcoord = (ix - nsensors + 0.5) * (module_x + module_spacing) +
0174 +(left ? -accum_xoffset : accum_xoffset);
0175
0176
0177 double module_z = x_supp_envelope.length() / 2.0 + total_thickness / 2;
0178 if (front)
0179 module_z *= -1;
0180
0181 string module_name = Form("module%d_%d_%d", module, ix, iy);
0182 DetElement mod_elt(lay_elt, module_name, module);
0183
0184
0185 string m_nam = Form("EndcapTOF_Module%d_%d_%d", module, ix, iy);
0186
0187 int ncomponents = 0;
0188
0189 Assembly m_vol(m_nam);
0190 m_vol.setVisAttributes(description.visAttributes(x_modCurr.visStr()));
0191
0192 double thickness_so_far = 0.0;
0193 double thickness_sum = -total_thickness / 2.0;
0194 double thickness_carbonsupp = 0.0;
0195 int sensitive_id = 0;
0196 for (xml_coll_t mci(x_modCurr, _U(module_component)); mci; ++mci, ++ncomponents) {
0197 xml_comp_t x_comp = mci;
0198 xml_comp_t x_pos = x_comp.position(false);
0199 xml_comp_t x_rot = x_comp.rotation(false);
0200 const string c_nam =
0201 Form("component_%s_%s_ix%d_iy%d", x_comp.nameStr().c_str(), locStr.c_str(), ix, iy);
0202
0203 Box c_box(x_comp.width() / 2, x_comp.length() / 2, x_comp.thickness() / 2);
0204 Volume c_vol(c_nam, c_box, description.material(x_comp.materialStr()));
0205 if (x_comp.materialStr() == "CarbonFiber") {
0206 thickness_carbonsupp = x_comp.thickness();
0207 }
0208
0209 const double zoff = thickness_sum + x_comp.thickness() / 2.0;
0210 if (x_pos && x_rot) {
0211 Position c_pos(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff);
0212 RotationZYX c_rot(x_rot.z(0), x_rot.y(0), x_rot.x(0));
0213 pv = m_vol.placeVolume(c_vol, Transform3D(c_rot, c_pos));
0214 } else if (x_rot) {
0215 Position c_pos(0, 0, zoff);
0216 pv = m_vol.placeVolume(
0217 c_vol, Transform3D(RotationZYX(x_rot.z(0), x_rot.y(0), x_rot.x(0)), c_pos));
0218 } else if (x_pos) {
0219 pv = m_vol.placeVolume(c_vol, Position(x_pos.x(0), x_pos.y(0), x_pos.z(0) + zoff));
0220 } else {
0221 pv = m_vol.placeVolume(c_vol, Position(0, 0, zoff));
0222 }
0223 c_vol.setRegion(description, x_comp.regionStr());
0224 c_vol.setLimitSet(description, x_comp.limitsStr());
0225 c_vol.setVisAttributes(description, x_comp.visStr());
0226 if (x_comp.isSensitive()) {
0227 pv.addPhysVolID("idx", ix);
0228 pv.addPhysVolID("idy", iy);
0229 pv.addPhysVolID("ids", sensitive_id);
0230 ++sensitive_id;
0231
0232 c_vol.setSensitiveDetector(sens);
0233 module_thicknesses[m_nam] = {thickness_so_far + x_comp.thickness() / 2.0,
0234 total_thickness - thickness_so_far -
0235 x_comp.thickness() / 2.0};
0236
0237
0238 Vector3D u(-1., 0., 0.);
0239 Vector3D v(0., -1., 0.);
0240 Vector3D n(0., 0., 1.);
0241
0242
0243
0244 double inner_thickness = module_thicknesses[m_nam][0];
0245 double outer_thickness = module_thicknesses[m_nam][1];
0246
0247 SurfaceType type(SurfaceType::Sensitive);
0248
0249 VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n);
0250
0251 DetElement comp_de(mod_elt,
0252 std::string("de_") + pv.volume().name() + "_" +
0253 std::to_string(sensitive_id),
0254 module);
0255 comp_de.setPlacement(pv);
0256
0257 auto& comp_de_params =
0258 DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(comp_de);
0259 comp_de_params.set<string>("axis_definitions", "XYZ");
0260 volSurfaceList(comp_de)->push_back(surf);
0261
0262
0263 }
0264 bool keep_same_layer = getAttrOrDefault<bool>(x_comp, _Unicode(keep_layer), false);
0265 if (!keep_same_layer) {
0266 thickness_sum += x_comp.thickness();
0267 thickness_so_far += x_comp.thickness();
0268
0269 if (x_pos) {
0270 thickness_sum += x_pos.z(0);
0271 thickness_so_far += x_pos.z(0);
0272 }
0273 }
0274 }
0275
0276 if (front) {
0277
0278
0279 const string suppb_nam =
0280 Form("suppbar_%d_%d", ix, iy);
0281 Box suppb_box((module_x + module_spacing) / 2, thickness_carbonsupp / 2,
0282 x_supp_envelope.length() / 2);
0283 Volume suppb_vol(suppb_nam, suppb_box, carbon);
0284 Transform3D trsupp(RotationZYX(0, 0, 0),
0285 Position(xcoord, ycoord + module_y / 2 - module_overlap / 2, 0));
0286 suppb_vol.setVisAttributes(description, "AnlGray");
0287
0288 pv = lay_vol.placeVolume(suppb_vol, trsupp);
0289 }
0290
0291
0292 Transform3D tr(RotationZYX(M_PI / 2, 0, 0), Position(xcoord, ycoord, module_z));
0293
0294 pv = lay_vol.placeVolume(m_vol, tr);
0295 pv.addPhysVolID("module", module);
0296 mod_elt.setPlacement(pv);
0297 }
0298 ycoord -= (module_y - module_overlap);
0299 ++iy;
0300 }
0301 }
0302 }
0303
0304 pv = assembly.placeVolume(lay_vol, lay_pos);
0305 pv.addPhysVolID("layer", lay_id);
0306 lay_elt.setAttributes(description, lay_vol, x_layer.regionStr(), x_layer.limitsStr(),
0307 x_layer.visStr());
0308 lay_elt.setPlacement(pv);
0309
0310 pv = description.pickMotherVolume(sdet).placeVolume(assembly, Position(0, 0, zPos));
0311 pv.addPhysVolID("system", det_id);
0312 sdet.setPlacement(pv);
0313
0314 return sdet;
0315 }
0316
0317
0318
0319 DECLARE_DETELEMENT(epic_TOFEndcap, create_detector)