File indexing completed on 2025-07-11 07:53:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
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
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
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
0065 dd4hep::xml::setDetectorTypeFlag(x_det, sdet);
0066 auto& params = DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(sdet);
0067
0068
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
0076
0077
0078 Assembly assembly(det_name);
0079
0080 sens.setType("tracker");
0081
0082
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
0119 }
0120
0121
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
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
0142 Assembly m_vol(m_nam);
0143 volumes[m_nam] = m_vol;
0144 m_vol.setVisAttributes(description.visAttributes(x_mod.visStr()));
0145
0146
0147 if (x_mod.hasChild(_U(frame))) {
0148 xml_comp_t m_frame = x_mod.child(_U(frame));
0149
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
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
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
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
0243
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
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
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
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
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
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
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
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
0350 Vector3D u(-1., 0., 0.);
0351 Vector3D v(0., -1., 0.);
0352 Vector3D n(0., 0., 1.);
0353
0354
0355
0356
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
0363
0364
0365 VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n);
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
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
0399 double sensors_xdist = getAttrOrDefault<double>(x_comp_t, _Unicode(xdist), x_comp.width());
0400
0401 double sensors_ydist = getAttrOrDefault<double>(x_comp_t, _Unicode(ydist), x_comp.length());
0402
0403 int nsensors_x = getAttrOrDefault<int>(x_comp_t, _Unicode(nx), 1);
0404
0405 int nsensors_y = getAttrOrDefault<int>(x_comp_t, _Unicode(ny), 1);
0406
0407 double start_x = getAttrOrDefault<double>(x_comp_t, _Unicode(start_x), 0);
0408
0409 double start_y = getAttrOrDefault<double>(x_comp_t, _Unicode(start_y), 0);
0410
0411 double start_z = getAttrOrDefault<double>(x_comp_t, _Unicode(start_z), 0);
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
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
0433
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
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;
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));
0458
0459
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
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));
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);
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();
0484 double phi_tilt = x_layout.phi_tilt();
0485 double rc = x_layout.rc();
0486 int nphi = x_layout.nphi();
0487 double rphi_dr = x_layout.dr();
0488 double phi_incr = (M_PI * 2) / nphi;
0489 double phic = phi0;
0490 double z0 = z_layout.z0();
0491 double nz = z_layout.nz();
0492 double z_dr = z_layout.dr();
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
0499
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
0510
0511
0512 double z_incr = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0;
0513
0514 double module_z = -z0;
0515 int module = 1;
0516
0517
0518 for (int ii = 0; ii < nphi; ii++) {
0519 double dx = z_dr * std::cos(phic + phi_tilt);
0520 double dy = z_dr * std::sin(phic + phi_tilt);
0521 double x = rc * std::cos(phic);
0522 double y = rc * std::sin(phic);
0523
0524
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
0544
0545
0546
0547 volSurfaceList(comp_de)->push_back(volplane_surfaces[m_nam][ic]);
0548 }
0549
0550
0551 module++;
0552
0553 x += dx;
0554 y += dy;
0555
0556 dx *= -1;
0557 dy *= -1;
0558
0559 module_z += z_incr;
0560 }
0561 phic += phi_incr;
0562 rc += rphi_dr;
0563 rphi_dr *= -1;
0564 module_z = -z0;
0565 }
0566
0567 pv = assembly.placeVolume(lay_vol, lay_pos);
0568 pv.addPhysVolID("layer", lay_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);
0577 sdet.setPlacement(pv);
0578 return sdet;
0579 }
0580
0581
0582
0583 DECLARE_DETELEMENT(epic_TOFBarrel, create_TOFBarrel)