File indexing completed on 2025-11-04 09:27:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include "DD4hep/DetFactoryHelper.h"
0020 #include "DD4hep/Printout.h"
0021 #include "DD4hep/Shapes.h"
0022 #include "DD4hepDetectorHelper.h"
0023 #include "DDRec/DetectorData.h"
0024 #include "DDRec/Surface.h"
0025 #include "XML/Layering.h"
0026 #include "XML/Utilities.h"
0027 #include <array>
0028
0029 using namespace std;
0030 using namespace dd4hep;
0031 using namespace dd4hep::rec;
0032
0033
0034
0035
0036
0037
0038
0039
0040 static Ref_t create_BarrelPlanarMPGDTracker_geo(Detector& description, xml_h e,
0041 SensitiveDetector sens) {
0042 typedef vector<PlacedVolume> Placements;
0043 xml_det_t x_det = e;
0044
0045 int det_id = x_det.id();
0046 string det_name = x_det.nameStr();
0047 DetElement sdet(det_name, det_id);
0048 map<string, Volume> volumes;
0049 map<string, Placements> sensitives;
0050 map<string, std::vector<rec::VolPlane>> volplane_surfaces;
0051 PlacedVolume pv;
0052 dd4hep::xml::Dimension dimensions(x_det.dimensions());
0053 xml_dim_t mpgd_pos = x_det.position();
0054 Assembly assembly(det_name);
0055
0056 double pcb_feb_ext = 0.0;
0057
0058
0059 dd4hep::xml::setDetectorTypeFlag(x_det, sdet);
0060 auto& params = DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(sdet);
0061
0062
0063 for (xml_coll_t bmat(x_det, _Unicode(boundary_material)); bmat; ++bmat) {
0064 xml_comp_t x_boundary_material = bmat;
0065 DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_boundary_material, params,
0066 "boundary_material");
0067 }
0068
0069 map<string, std::array<double, 2>> module_thicknesses;
0070 sens.setType("tracker");
0071
0072
0073 for (xml_coll_t mi(x_det, _U(module)); mi; ++mi) {
0074 xml_comp_t x_mod = mi;
0075 string m_nam = x_mod.nameStr();
0076
0077 if (volumes.find(m_nam) != volumes.end()) {
0078 printout(ERROR, "BarrelPlanarMPGDTracker_geo",
0079 string((string("Module with named ") + m_nam + string(" already exists."))).c_str());
0080 throw runtime_error("Logics error in building modules.");
0081 }
0082
0083 int ncomponents = 0;
0084 int sensor_number = 1;
0085 double total_thickness = 0;
0086
0087
0088 xml_coll_t ci(x_mod, _U(module_component));
0089 for (ci.reset(), total_thickness = 0.0; ci; ++ci) {
0090 total_thickness += xml_comp_t(ci).thickness();
0091 }
0092
0093 Assembly m_vol(m_nam);
0094 volumes[m_nam] = m_vol;
0095 m_vol.setVisAttributes(description, x_mod.visStr());
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 double frame_width = 0;
0108 if (x_mod.hasChild(_U(frame))) {
0109 xml_comp_t m_frame = x_mod.child(_U(frame));
0110 frame_width = m_frame.width();
0111 }
0112
0113 double thickness_so_far = 0.0;
0114 double thickness_sum = -total_thickness / 2.0;
0115 double max_component_width = 0;
0116 double max_component_length = 0;
0117 double gas_thickness = 0.0;
0118 for (xml_coll_t mci(x_mod, _U(module_component)); mci; ++mci, ++ncomponents) {
0119 xml_comp_t x_comp = mci;
0120 string c_nam = _toString(ncomponents, "component%d");
0121 string comp_name = x_comp.nameStr();
0122
0123 double box_width = x_comp.width();
0124 double box_length = x_comp.length();
0125 Box c_box;
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139 if ((comp_name == "DriftGap" || comp_name == "WindowGasGap")) {
0140 box_width = x_comp.width() - 2.0 * frame_width;
0141 box_length = x_comp.length() - 2.0 * frame_width;
0142 max_component_width = box_width;
0143 max_component_length = box_length;
0144 gas_thickness += x_comp.thickness();
0145 c_box = {box_width / 2, box_length / 2, x_comp.thickness() / 2};
0146 printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "gas: %s", comp_name.c_str());
0147 printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_width: %f", box_width);
0148 printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_length: %f", box_length);
0149 printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_thickness: %f", x_comp.thickness());
0150 } else {
0151 c_box = {x_comp.width() / 2, x_comp.length() / 2, x_comp.thickness() / 2};
0152 printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "Not gas: %s", comp_name.c_str());
0153 printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_width: %f", x_comp.width());
0154 printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_length: %f", x_comp.length());
0155 printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "box_comp_thickness: %f",
0156 x_comp.thickness());
0157 }
0158 Volume c_vol{c_nam, c_box, description.material(x_comp.materialStr())};
0159
0160 c_vol.setRegion(description, x_comp.regionStr());
0161 c_vol.setLimitSet(description, x_comp.limitsStr());
0162 c_vol.setVisAttributes(description, x_comp.visStr());
0163
0164 pcb_feb_ext = x_comp.offset();
0165
0166 pv = m_vol.placeVolume(
0167 c_vol, Position(0, -pcb_feb_ext / 2.0, thickness_sum + x_comp.thickness() / 2.0));
0168
0169 if (x_comp.isSensitive()) {
0170 pv.addPhysVolID("sensor", sensor_number++);
0171 c_vol.setSensitiveDetector(sens);
0172 sensitives[m_nam].push_back(pv);
0173 module_thicknesses[m_nam] = {thickness_so_far + x_comp.thickness() / 2.0,
0174 total_thickness - thickness_so_far - x_comp.thickness() / 2.0};
0175
0176 Vector3D u(-1., 0., 0.);
0177 Vector3D v(0., -1., 0.);
0178 Vector3D n(0., 0., 1.);
0179
0180
0181
0182 double inner_thickness = module_thicknesses[m_nam][0];
0183 double outer_thickness = module_thicknesses[m_nam][1];
0184
0185 SurfaceType type(rec::SurfaceType::Sensitive);
0186
0187 VolPlane surf(c_vol, type, inner_thickness, outer_thickness, u, v, n);
0188 volplane_surfaces[m_nam].push_back(surf);
0189 }
0190 thickness_sum += x_comp.thickness();
0191 thickness_so_far += x_comp.thickness();
0192 }
0193
0194 if (x_mod.hasChild(_U(frame))) {
0195 xml_comp_t m_frame = x_mod.child(_U(frame));
0196 double frame_thickness = getAttrOrDefault<double>(m_frame, _U(thickness), total_thickness);
0197
0198 Box lframe_box{m_frame.width() / 2.0, (max_component_length + 2.0 * m_frame.width()) / 2.0,
0199 frame_thickness / 2.0};
0200 Box rframe_box{m_frame.width() / 2.0, (max_component_length + 2.0 * m_frame.width()) / 2.0,
0201 frame_thickness / 2.0};
0202 Box tframe_box{max_component_width / 2.0, m_frame.width() / 2.0, frame_thickness / 2.0};
0203 Box bframe_box{max_component_width / 2.0, m_frame.width() / 2.0, frame_thickness / 2.0};
0204
0205
0206
0207 Volume lframe_vol{"left_frame", lframe_box, description.material(m_frame.materialStr())};
0208 Volume rframe_vol{"right_frame", rframe_box, description.material(m_frame.materialStr())};
0209 Volume tframe_vol{"top_frame", tframe_box, description.material(m_frame.materialStr())};
0210 Volume bframe_vol{"bottom_frame", bframe_box, description.material(m_frame.materialStr())};
0211
0212 lframe_vol.setVisAttributes(description, m_frame.visStr());
0213 rframe_vol.setVisAttributes(description, m_frame.visStr());
0214 tframe_vol.setVisAttributes(description, m_frame.visStr());
0215 bframe_vol.setVisAttributes(description, m_frame.visStr());
0216
0217 printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "frame_thickness: %f", frame_thickness);
0218 printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "total_thickness: %f", total_thickness);
0219 printout(DEBUG, "BarrelPlanarMPGDTracker_geo", "frame_thickness + total_thickness: %f",
0220 frame_thickness + total_thickness);
0221
0222 m_vol.placeVolume(lframe_vol, Position(frame_width / 2.0 + max_component_width / 2, 0.0,
0223 frame_thickness / 2.0 - total_thickness / 2.0 -
0224 gas_thickness / 2.0));
0225 m_vol.placeVolume(rframe_vol, Position(-frame_width / 2.0 - max_component_width / 2.0, 0.0,
0226 frame_thickness / 2.0 - total_thickness / 2.0 -
0227 gas_thickness / 2.0));
0228 m_vol.placeVolume(tframe_vol, Position(0.0, frame_width / 2.0 + max_component_length / 2,
0229 frame_thickness / 2.0 - total_thickness / 2.0 -
0230 gas_thickness / 2.0));
0231 m_vol.placeVolume(bframe_vol, Position(0.0, -frame_width / 2.0 - max_component_length / 2.0,
0232 frame_thickness / 2.0 - total_thickness / 2.0 -
0233 gas_thickness / 2.0));
0234 }
0235 }
0236
0237
0238 for (xml_coll_t li(x_det, _U(layer)); li; ++li) {
0239 xml_comp_t x_layer = li;
0240 xml_comp_t x_layout = x_layer.child(_U(rphi_layout));
0241 xml_comp_t z_layout = x_layer.child(_U(z_layout));
0242 int lay_id = x_layer.id();
0243 string m_nam = x_layer.moduleStr();
0244 string lay_nam = det_name + _toString(x_layer.id(), "_layer%d");
0245 xml_comp_t envelope_tolerance = x_layer.child(_Unicode(envelope_tolerance), false);
0246 double envelope_r_min = 0;
0247 double envelope_r_max = 0;
0248 double envelope_z_min = 0;
0249 double envelope_z_max = 0;
0250 if (envelope_tolerance) {
0251 envelope_r_min = getAttrOrDefault(envelope_tolerance, _Unicode(r_min), 0);
0252 envelope_r_max = getAttrOrDefault(envelope_tolerance, _Unicode(r_max), 0);
0253 envelope_z_min = getAttrOrDefault(envelope_tolerance, _Unicode(z_min), 0);
0254 envelope_z_max = getAttrOrDefault(envelope_tolerance, _Unicode(z_max), 0);
0255 }
0256
0257 double phi0 = x_layout.phi0();
0258 double phi_tilt = x_layout.phi_tilt();
0259 double rc = x_layout.rc();
0260 int nphi = x_layout.nphi();
0261 double rphi_dr = x_layout.dr();
0262 double phi_incr = (2 * M_PI) / nphi;
0263 double phic = phi0;
0264 int nz = 2;
0265 double z_dr = z_layout.dr();
0266 double z0 = z_layout.z0();
0267
0268 Assembly layer_assembly(lay_nam);
0269 Volume module_env = volumes[m_nam];
0270 DetElement lay_elt(sdet, lay_nam, lay_id);
0271 Placements& sensVols = sensitives[m_nam];
0272 auto& layerParams =
0273 DD4hepDetectorHelper::ensureExtension<dd4hep::rec::VariantParameters>(lay_elt);
0274
0275 pv = assembly.placeVolume(layer_assembly);
0276 pv.addPhysVolID("layer", lay_id);
0277 lay_elt.setPlacement(pv);
0278
0279 int module = 1;
0280
0281 for (int ii = 0; ii < nphi; ii++) {
0282 double xc = rc * std::cos(phic);
0283 double yc = rc * std::sin(phic);
0284 double dx = z_dr * std::cos(phic + phi_tilt);
0285 double dy = z_dr * std::sin(phic + phi_tilt);
0286
0287 for (int j = 0; j < nz; j++) {
0288 string module_name = _toString(module, "module%d");
0289 DetElement mod_elt(lay_elt, module_name, module);
0290 double mod_z = 0.5 * dimensions.length();
0291 double z_placement = mod_z - 0.5 * pcb_feb_ext -
0292 j * (nz * mod_z - pcb_feb_ext);
0293 double z_offset =
0294 z_placement > 0
0295 ? -z0 / 2.0
0296 : z0 / 2.0;
0297
0298 Transform3D tr(
0299 RotationZYX(0, ((M_PI / 2) - phic - phi_tilt), -M_PI / 2) * RotationZ(j * M_PI),
0300 Position(
0301 xc, yc,
0302 mpgd_pos.z() + z_placement +
0303 z_offset));
0304
0305 pv = layer_assembly.placeVolume(module_env, tr);
0306 pv.addPhysVolID("module", module);
0307 mod_elt.setPlacement(pv);
0308 for (size_t ic = 0; ic < sensVols.size(); ++ic) {
0309 PlacedVolume sens_pv = sensVols[ic];
0310 DetElement comp_de(mod_elt, std::string("de_") + sens_pv.volume().name(), module);
0311 comp_de.setPlacement(sens_pv);
0312 }
0313
0314 module++;
0315
0316 xc += dx;
0317 yc += dy;
0318 }
0319
0320 phic += phi_incr;
0321 rc += rphi_dr;
0322 }
0323 layer_assembly->GetShape()->ComputeBBox();
0324 layerParams.set<double>("envelope_r_min", envelope_r_min);
0325 layerParams.set<double>("envelope_r_max", envelope_r_max);
0326 layerParams.set<double>("envelope_z_min", envelope_z_min);
0327 layerParams.set<double>("envelope_z_max", envelope_z_max);
0328
0329 for (xml_coll_t lmat(x_layer, _Unicode(layer_material)); lmat; ++lmat) {
0330 xml_comp_t x_layer_material = lmat;
0331 DD4hepDetectorHelper::xmlToProtoSurfaceMaterial(x_layer_material, layerParams,
0332 "layer_material");
0333 }
0334 }
0335 sdet.setAttributes(description, assembly, x_det.regionStr(), x_det.limitsStr(), x_det.visStr());
0336 assembly.setVisAttributes(description.invisible());
0337 pv = description.pickMotherVolume(sdet).placeVolume(assembly);
0338 pv.addPhysVolID("system", det_id);
0339 sdet.setPlacement(pv);
0340 return sdet;
0341 }
0342
0343
0344
0345 DECLARE_DETELEMENT(epic_OuterMPGDBarrel, create_BarrelPlanarMPGDTracker_geo)