File indexing completed on 2026-05-30 08:05:09
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include "DD4hep/DetFactoryHelper.h"
0018 #include "Math/Point2D.h"
0019 #include "TGeoPolygon.h"
0020 #include "XML/Layering.h"
0021 #include "XML/Utilities.h"
0022 #include <functional>
0023
0024 using namespace dd4hep;
0025
0026 typedef ROOT::Math::XYPoint Point;
0027
0028 struct FiberGrid {
0029 int ix = 0, iy = 0;
0030 std::vector<Point> points;
0031 Point mean_centroid = Point(0., 0.);
0032 Assembly* assembly_ptr = nullptr;
0033
0034
0035 FiberGrid(int i, int j, const std::vector<Point>& pts) : ix(i), iy(j), points(pts) {
0036 if (pts.empty()) {
0037 return;
0038 }
0039
0040 double mx = 0., my = 0.;
0041 for (auto& p : pts) {
0042 mx += p.x();
0043 my += p.y();
0044 }
0045 mx /= static_cast<double>(pts.size());
0046 my /= static_cast<double>(pts.size());
0047 mean_centroid = Point(mx, my);
0048 };
0049 };
0050
0051 std::vector<Point> fiberPositions(double r, double sx, double sz, double trx, double trz,
0052 double phi, bool shift_first = false, double stol = 1e-2);
0053 std::vector<FiberGrid> gridPoints(int div_n_phi, double div_dr, double x, double z, double phi);
0054
0055
0056 void buildFibers(Detector& desc, SensitiveDetector& sens, Volume& mother, int layer_nunber,
0057 xml_comp_t x_fiber, const std::tuple<double, double, double, double>& dimensions);
0058 void buildSupport(Detector& desc, Volume& mother, xml_comp_t x_support,
0059 const std::tuple<double, double, double, double>& dimensions);
0060
0061
0062 static Ref_t create_detector(Detector& desc, xml_h e, SensitiveDetector sens) {
0063 Layering layering(e);
0064 xml_det_t x_det = e;
0065 Material air = desc.air();
0066 int det_id = x_det.id();
0067 double offset = x_det.attr<double>(_Unicode(offset));
0068 xml_comp_t x_dim = x_det.dimensions();
0069 int nsides = x_dim.numsides();
0070 double inner_r = x_dim.rmin();
0071 double dphi = (2 * M_PI / nsides);
0072 double hphi = dphi / 2;
0073 std::string det_name = x_det.nameStr();
0074
0075 DetElement sdet(det_name, det_id);
0076 Volume motherVol = desc.pickMotherVolume(sdet);
0077
0078
0079 dd4hep::xml::setDetectorTypeFlag(x_det, sdet);
0080
0081 Assembly envelope(det_name);
0082 Transform3D tr_global = Translation3D(0, 0, offset) * RotationZ(0);
0083 PlacedVolume env_phv = motherVol.placeVolume(envelope, tr_global);
0084 sens.setType("calorimeter");
0085
0086 env_phv.addPhysVolID("system", det_id);
0087 sdet.setPlacement(env_phv);
0088
0089
0090 DetElement sector_det("sector0", det_id);
0091 Assembly mod_vol("sector");
0092 sector_det.setTypeFlag(sdet.typeFlag());
0093
0094
0095 double l_pos_z = inner_r;
0096 {
0097
0098 double tan_hphi = std::tan(hphi);
0099 double l_dim_y = x_dim.z() / 2.;
0100
0101
0102 int l_num = 1;
0103 for (xml_coll_t li(x_det, _U(layer)); li; ++li) {
0104 xml_comp_t x_layer = li;
0105 int repeat = x_layer.repeat();
0106 double l_space_between = getAttrOrDefault(x_layer, _Unicode(space_between), 0.);
0107 double l_space_before = getAttrOrDefault(x_layer, _Unicode(space_before), 0.);
0108 l_pos_z += l_space_before;
0109
0110 for (int j = 0; j < repeat; j++) {
0111 std::string l_name = Form("layer%d", l_num);
0112 double l_thickness = layering.layer(l_num - 1)->thickness();
0113 double l_dim_x = tan_hphi * l_pos_z;
0114 l_pos_z += l_thickness;
0115
0116 Position l_pos(0, 0, l_pos_z - l_thickness / 2.);
0117 double l_trd_x1 = l_dim_x;
0118 double l_trd_x2 = l_dim_x + l_thickness * tan_hphi;
0119 double l_trd_y1 = l_dim_y;
0120 double l_trd_y2 = l_trd_y1;
0121 double l_trd_z = l_thickness / 2;
0122 Trapezoid l_shape(l_trd_x1, l_trd_x2, l_trd_y1, l_trd_y2, l_trd_z);
0123 Volume l_vol(l_name, l_shape, air);
0124 DetElement layer(sector_det, l_name, det_id);
0125 layer.setTypeFlag(sdet.typeFlag());
0126
0127
0128 int s_num = 1;
0129 double s_pos_z = -(l_thickness / 2.);
0130 for (xml_coll_t si(x_layer, _U(slice)); si; ++si) {
0131 xml_comp_t x_slice = si;
0132 std::string s_name = Form("slice%d", s_num);
0133 double s_thick = x_slice.thickness();
0134 double s_trd_x1 = l_dim_x + (s_pos_z + l_thickness / 2) * tan_hphi;
0135 double s_trd_x2 = l_dim_x + (s_pos_z + l_thickness / 2 + s_thick) * tan_hphi;
0136 double s_trd_y1 = l_trd_y1;
0137 double s_trd_y2 = s_trd_y1;
0138 double s_trd_z = s_thick / 2.;
0139 Trapezoid s_shape(s_trd_x1, s_trd_x2, s_trd_y1, s_trd_y2, s_trd_z);
0140 Volume s_vol(s_name, s_shape, desc.material(x_slice.materialStr()));
0141 DetElement slice(layer, s_name, det_id);
0142 slice.setTypeFlag(sdet.typeFlag());
0143
0144
0145 if (x_slice.hasChild(_Unicode(fiber))) {
0146 buildFibers(desc, sens, s_vol, l_num, x_slice.child(_Unicode(fiber)),
0147 {s_trd_x1, s_thick, l_dim_y, hphi});
0148 }
0149
0150 if (x_slice.isSensitive()) {
0151 s_vol.setSensitiveDetector(sens);
0152 }
0153 s_vol.setAttributes(desc, x_slice.regionStr(), x_slice.limitsStr(), x_slice.visStr());
0154
0155
0156 PlacedVolume slice_phv = l_vol.placeVolume(s_vol, Position(0, 0, s_pos_z + s_thick / 2));
0157 slice_phv.addPhysVolID("slice", s_num);
0158 slice.setPlacement(slice_phv);
0159
0160 s_pos_z += s_thick;
0161 ++s_num;
0162 }
0163
0164
0165 l_vol.setAttributes(desc, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr());
0166
0167 PlacedVolume layer_phv = mod_vol.placeVolume(l_vol, l_pos);
0168 layer_phv.addPhysVolID("layer", l_num);
0169 layer.setPlacement(layer_phv);
0170
0171 if (j < repeat - 1) {
0172 l_pos_z += l_space_between;
0173 }
0174 ++l_num;
0175 }
0176 }
0177 }
0178
0179 double phi = M_PI / nsides;
0180
0181 for (int i = 0; i < nsides; i++, phi -= dphi) {
0182
0183 Transform3D tr(RotationZYX(0, phi, M_PI * 0.5), Translation3D(0, 0, 0));
0184 PlacedVolume pv = envelope.placeVolume(mod_vol, tr);
0185 pv.addPhysVolID("sector", i + 1);
0186 DetElement sd = (i == 0) ? sector_det : sector_det.clone(Form("sector%d", i));
0187 sd.setTypeFlag(sdet.typeFlag());
0188 sd.setPlacement(pv);
0189 sdet.add(sd);
0190 }
0191
0192
0193 if (x_det.hasChild(_Unicode(sectors))) {
0194 xml_comp_t x_sectors = x_det.child(_Unicode(sectors));
0195 mod_vol.setVisAttributes(desc.visAttributes(x_sectors.visStr()));
0196 }
0197 if (x_det.hasChild(_U(support))) {
0198 buildSupport(desc, mod_vol, x_det.child(_U(support)), {inner_r, l_pos_z, x_dim.z(), hphi});
0199 }
0200
0201
0202 envelope.setAttributes(desc, x_det.regionStr(), x_det.limitsStr(), x_det.visStr());
0203 return sdet;
0204 }
0205
0206 void buildFibers(Detector& desc, SensitiveDetector& sens, Volume& s_vol, int layer_number,
0207 xml_comp_t x_fiber, const std::tuple<double, double, double, double>& dimensions) {
0208 auto [s_trd_x1, s_thick, s_length, hphi] = dimensions;
0209 double f_radius = getAttrOrDefault(x_fiber, _U(radius), 0.1 * cm);
0210 double f_cladding_thickness = getAttrOrDefault(x_fiber, _Unicode(cladding_thickness), 0.0 * cm);
0211 double f_spacing_x = getAttrOrDefault(x_fiber, _Unicode(spacing_x), 0.122 * cm);
0212 double f_spacing_z = getAttrOrDefault(x_fiber, _Unicode(spacing_z), 0.134 * cm);
0213 int grid_n_phi = getAttrOrDefault(x_fiber, _Unicode(grid_n_phi), 5);
0214 double grid_dr = getAttrOrDefault(x_fiber, _Unicode(grid_dr), 2.0 * cm);
0215 std::string f_id_grid = getAttrOrDefault<std::string>(x_fiber, _Unicode(identifier_grid), "grid");
0216 std::string f_id_fiber =
0217 getAttrOrDefault<std::string>(x_fiber, _Unicode(identifier_fiber), "fiber");
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227 double f_radius_core = f_radius - f_cladding_thickness;
0228 Tube f_tube_clad(0, f_radius, s_length);
0229 Volume f_vol_clad("fiber_vol", f_tube_clad, desc.material(x_fiber.materialStr()));
0230 Tube f_tube_core(0, f_radius_core, s_length);
0231 Volume f_vol_core("fiber_core_vol", f_tube_core, desc.material(x_fiber.materialStr()));
0232 if (x_fiber.isSensitive()) {
0233 f_vol_core.setSensitiveDetector(sens);
0234 }
0235 f_vol_core.setAttributes(desc, x_fiber.regionStr(), x_fiber.limitsStr(), x_fiber.visStr());
0236 f_vol_clad.placeVolume(f_vol_core);
0237
0238
0239 auto grids = gridPoints(grid_n_phi, grid_dr, s_trd_x1, s_thick, hphi);
0240 std::vector<int> f_id_count(grids.size(), 0);
0241
0242 auto f_pos = fiberPositions(f_radius, f_spacing_x, f_spacing_z, s_trd_x1, s_thick, hphi,
0243 (layer_number % 2 == 0));
0244
0245 struct Fiber {
0246 Point pos;
0247 bool assigned = false;
0248 Fiber(const Point& p) : pos(p) {};
0249 };
0250 std::vector<Fiber> fibers(f_pos.begin(), f_pos.end());
0251
0252
0253 for (auto& gr : grids) {
0254 Assembly grid_vol(Form("fiber_grid_%i_%i", gr.ix, gr.iy));
0255
0256
0257 int f_id = 1;
0258 for (auto& fi : fibers) {
0259 if (fi.assigned) {
0260 continue;
0261 }
0262
0263
0264 TGeoPolygon poly(gr.points.size());
0265 std::vector<double> vx, vy;
0266 std::transform(gr.points.begin(), gr.points.end(), back_inserter(vx), std::mem_fn(&Point::x));
0267 std::transform(gr.points.begin(), gr.points.end(), back_inserter(vy), std::mem_fn(&Point::y));
0268 poly.SetXY(vx.data(), vy.data());
0269 poly.FinishPolygon();
0270
0271 double f_xy[2] = {fi.pos.x(), fi.pos.y()};
0272 if (not poly.Contains(f_xy)) {
0273 continue;
0274 }
0275
0276
0277 auto p = fi.pos - gr.mean_centroid;
0278 auto clad_phv = grid_vol.placeVolume(f_vol_clad, Position(p.x(), p.y(), 0.));
0279 clad_phv.addPhysVolID(f_id_fiber, f_id);
0280 fi.assigned = true;
0281 f_id++;
0282 }
0283
0284
0285 if (f_id > 1) {
0286
0287 Transform3D gr_tr(RotationZYX(0., 0., M_PI * 0.5),
0288 Position(gr.mean_centroid.x(), 0., gr.mean_centroid.y()));
0289 auto grid_phv = s_vol.placeVolume(grid_vol, gr_tr);
0290 grid_phv.addPhysVolID(f_id_grid, gr.ix + gr.iy * grid_n_phi + 1);
0291 grid_vol.ptr()->Voxelize("");
0292 }
0293 }
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306 }
0307
0308
0309
0310 void buildSupport(Detector& desc, Volume& mod_vol, xml_comp_t x_support,
0311 const std::tuple<double, double, double, double>& dimensions) {
0312 auto [inner_r, pos_z, sector_length, hphi] = dimensions;
0313 double support_thickness = getAttrOrDefault(x_support, _Unicode(thickness), 3. * cm);
0314 auto material = desc.material(x_support.materialStr());
0315 double trd_y = sector_length / 2.;
0316 double trd_x1_support = std::tan(hphi) * pos_z;
0317 double trd_x2_support = std::tan(hphi) * (pos_z + support_thickness);
0318
0319 Trapezoid s_shape(trd_x1_support, trd_x2_support, trd_y, trd_y, support_thickness / 2.);
0320 Volume s_vol("support_layer", s_shape, material);
0321 s_vol.setVisAttributes(desc.visAttributes(x_support.visStr()));
0322 mod_vol.placeVolume(s_vol, Position(0.0, 0.0, pos_z + support_thickness / 2.));
0323 }
0324
0325
0326 std::vector<Point> fiberPositions(double r, double sx, double sz, double trx, double trz,
0327 double phi, bool shift, double stol) {
0328
0329
0330
0331
0332
0333
0334
0335 std::vector<Point> positions;
0336 int z_layers = floor((trz / 2 - r - stol) / sz);
0337
0338 double px = 0., pz = 0.;
0339 int start_line = shift ? 1 : 0;
0340
0341 for (int l = -z_layers; l < z_layers + 1; l++) {
0342 std::vector<Point> xline;
0343 pz = l * sz;
0344 double x_max = trx + (trz / 2. + pz) * tan(phi) - stol;
0345 (abs(l) % 2 == start_line) ? px = 0. : px = sx / 2;
0346
0347 while (px < (x_max - r)) {
0348 xline.push_back(Point(px, pz));
0349 if (px != 0.)
0350 xline.push_back(Point(-px, pz));
0351 px += sx;
0352 }
0353
0354
0355 sort(xline.begin(), xline.end(),
0356 [](const Point& p1, const Point& p2) { return p1.x() < p2.x(); });
0357 positions.insert(positions.end(), xline.begin(), xline.end());
0358 }
0359 return positions;
0360 }
0361
0362
0363
0364 std::vector<FiberGrid> gridPoints(int div_n_phi, double div_dr, double trd_x1, double height,
0365 double phi) {
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380 int nph = div_n_phi;
0381 int nr = floor(height / div_dr);
0382 if (nr == 0) {
0383 nr++;
0384 }
0385
0386
0387 std::vector<FiberGrid> results;
0388 double dr = height / nr;
0389
0390 for (int ir = 0; ir <= nr; ir++) {
0391 for (int iph = 0; iph <= nph; iph++) {
0392 double A_y = -height / 2. + ir * dr;
0393 double B_y = -height / 2. + (ir + 1) * dr;
0394
0395 double botl_dr = 2 * (trd_x1 + ir * dr * tan(phi));
0396 double topl_dr = 2 * (trd_x1 + (ir + 1) * dr * tan(phi));
0397
0398 double botl_dph_dr = botl_dr / nph;
0399 double topl_dph_dr = topl_dr / nph;
0400
0401 double A_x = -botl_dr / 2. + iph * botl_dph_dr;
0402 double B_x = -topl_dr / 2. + iph * topl_dph_dr;
0403
0404 double C_y = B_y;
0405 double D_y = A_y;
0406 double C_x = B_x + topl_dph_dr;
0407 double D_x = A_x + botl_dph_dr;
0408
0409 auto A = Point(A_x, A_y);
0410 auto B = Point(B_x, B_y);
0411 auto C = Point(C_x, C_y);
0412 auto D = Point(D_x, D_y);
0413
0414
0415 results.emplace_back(FiberGrid(iph, ir, {A, B, C, D}));
0416 }
0417 }
0418
0419 return results;
0420 }
0421
0422 DECLARE_DETELEMENT(epic_EcalBarrelScFi, create_detector)