File indexing completed on 2025-07-14 08:15:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include "DD4hep/DetFactoryHelper.h"
0013 #include "DD4hep/OpticalSurfaces.h"
0014 #include "DD4hep/Printout.h"
0015 #include "DDRec/DetectorData.h"
0016 #include "DDRec/Surface.h"
0017
0018 #include <XML/Helper.h>
0019 #include "XML/Layering.h"
0020 #include "TVector3.h"
0021
0022 #include "TGeoElement.h"
0023 #include "TGeoManager.h"
0024 #include "TInterpreter.h"
0025 #include "TUri.h"
0026
0027 using namespace std;
0028 using namespace dd4hep;
0029 using namespace dd4hep::rec;
0030 using namespace dd4hep::detail;
0031
0032 static Ref_t createDetector(Detector& description, xml_h e, SensitiveDetector sens) {
0033
0034 xml_det_t x_det = e;
0035 int det_id = x_det.id();
0036
0037 string det_name = x_det.nameStr();
0038 Material air = description.air();
0039
0040 DetElement sdet(det_name, det_id);
0041
0042 std::vector<double> rmins = {100, 100};
0043 std::vector<double> rmaxs = {1300, 1300};
0044 std::vector<double> zs = {-5000, 5000};
0045
0046 sens.setType("tracker");
0047 description.invisible();
0048
0049 xml::DetElement detElem = e;
0050 std::string detName = detElem.nameStr();
0051 xml::Component dims = detElem.dimensions();
0052
0053 xml_dim_t x_par(x_det.child(_U(parent)));
0054
0055 string name = x_det.nameStr();
0056 string par_nam = x_par.nameStr();
0057 DetElement det_parent = description.detector(par_nam);
0058
0059 Volume mother = det_parent.volume();
0060 PlacedVolume pv;
0061
0062 int id = x_det.hasAttr(_U(id)) ? x_det.id() : 0;
0063 xml_dim_t x_pos(x_det.child(_U(position), false));
0064 xml_dim_t x_rot(x_det.child(_U(rotation), false));
0065
0066 Tube pfRICH_air_volume(0.0, 65.0, 25.0);
0067
0068 Rotation3D rot(RotationZYX(0, M_PI, 0));
0069 Transform3D transform(rot, Position(0, 0, -149));
0070
0071
0072
0073
0074 OpticalSurfaceManager surfMgr = description.surfaceManager();
0075
0076
0077 auto sensorElem = detElem.child(_Unicode(sensors)).child(_Unicode(module));
0078 auto sensorMat = description.material(sensorElem.attr<std::string>(_Unicode(material)));
0079 auto sensorVis = description.visAttributes(sensorElem.attr<std::string>(_Unicode(vis)));
0080 auto sensorSurf = surfMgr.opticalSurface(sensorElem.attr<std::string>(_Unicode(surface)));
0081 double sensorSide = sensorElem.attr<double>(_Unicode(side));
0082 double sensorThickness = sensorElem.attr<double>(_Unicode(thickness));
0083 auto readoutName = detElem.attr<std::string>(_Unicode(readout));
0084
0085 auto HRPPD_WindowMat = description.material(sensorElem.attr<std::string>(_Unicode(windowmat)));
0086 auto HRPPD_PCBMat = description.material(sensorElem.attr<std::string>(_Unicode(pcbmat)));
0087 auto HRPPD_MPDMat = description.material(sensorElem.attr<std::string>(_Unicode(mpdmat)));
0088 auto HRPPD_ASICMat = description.material(sensorElem.attr<std::string>(_Unicode(asicmat)));
0089
0090 double vesselRmin0 = dims.attr<double>(_Unicode(rmin0));
0091 double vesselRmin1 = dims.attr<double>(_Unicode(rmin1));
0092 double vesselRmax0 = dims.attr<double>(_Unicode(rmax0));
0093 double vesselRmax1 = dims.attr<double>(_Unicode(rmax1));
0094
0095 int imod = 0;
0096
0097 auto gasvolMat = description.material(detElem.attr<std::string>(_Unicode(gas)));
0098 auto gasvolVis = description.visAttributes("DRICH_gas_vis");
0099 auto vesselVis = description.visAttributes(detElem.attr<std::string>(_Unicode(vis_vessel)));
0100
0101 double windowThickness = dims.attr<double>(_Unicode(window_thickness));
0102 double wallThickness = dims.attr<double>(_Unicode(wall_thickness));
0103
0104 double proximityGap = dims.attr<double>(_Unicode(proximity_gap));
0105
0106 long debug_optics_mode = description.constantAsLong("PFRICH_debug_optics");
0107
0108 bool debug_optics = debug_optics_mode > 0;
0109
0110 auto radiatorElem = detElem.child(_Unicode(radiator));
0111 double radiatorFrontplane = radiatorElem.attr<double>(_Unicode(frontplane));
0112
0113 auto aerogelElem = radiatorElem.child(_Unicode(aerogel));
0114 double aerogelThickness = aerogelElem.attr<double>(_Unicode(thickness));
0115
0116 double radiatorRmin = radiatorElem.attr<double>(_Unicode(rmin));
0117 double radiatorRmax = radiatorElem.attr<double>(_Unicode(rmax));
0118
0119 auto filterElem = radiatorElem.child(_Unicode(filter));
0120
0121 double airgapThickness = 0.1;
0122 double filterThickness = 1;
0123
0124 auto aerogelMat = description.material(aerogelElem.attr<std::string>(_Unicode(material)));
0125 auto filterMat = description.material(filterElem.attr<std::string>(_Unicode(material)));
0126
0127 double vesselLength = dims.attr<double>(_Unicode(length));
0128 auto originFront = Position(0., 0., vesselLength / 2.0);
0129 double sensorZpos = radiatorFrontplane - aerogelThickness - proximityGap - 0.5 * sensorThickness;
0130 auto sensorPlanePos = Position(0., 0., sensorZpos) + originFront;
0131
0132
0133
0134
0135
0136
0137
0138 std::vector<std::string> sensorIDfields = {"module"};
0139 const auto& readoutCoder = *description.readout(readoutName).idSpec().decoder();
0140
0141 uint64_t cellMask = 0;
0142 for (const auto& idField : sensorIDfields)
0143 cellMask |= readoutCoder[idField].mask();
0144 description.add(Constant("PFRICH_cell_mask", std::to_string(cellMask)));
0145
0146 auto encodeSensorID = [&readoutCoder](auto ids) {
0147 uint64_t enc = 0;
0148 for (const auto& [idField, idValue] : ids)
0149 enc |= uint64_t(idValue) << readoutCoder[idField].offset();
0150 return enc;
0151 };
0152
0153 auto mirrorElem = detElem.child(_Unicode(mirror));
0154 auto mirrorMat = description.material(mirrorElem.attr<std::string>(_Unicode(material)));
0155 auto mirrorVis = description.visAttributes(mirrorElem.attr<std::string>(_Unicode(vis)));
0156
0157 Cone mirror_cone(vesselLength / 2.0, vesselRmax1 - 7, vesselRmax1 - 7 + 0.3, vesselRmax1 - 13,
0158 vesselRmax1 - 13 + 0.3);
0159
0160
0161
0162 auto vesselMat = description.material(detElem.attr<std::string>(_Unicode(material)));
0163 auto vesselGas = description.material(detElem.attr<std::string>(_Unicode(gas)));
0164
0165
0166
0167 float _FLANGE_EPIPE_DIAMETER_ = description.constant<double>("FLANGE_EPIPE_DIAMETER");
0168 float _FLANGE_HPIPE_DIAMETER_ = description.constant<double>("FLANGE_HPIPE_DIAMETER");
0169 float _FLANGE_HPIPE_OFFSET_ = description.constant<double>("FLANGE_HPIPE_OFFSET");
0170 double clearance = description.constant<double>("CLEARANCE");
0171
0172
0173 float _CONICAL_MIRROR_INNER_RADIUS_ = description.constant<double>("CONICAL_MIRROR_INNER_RADIUS");
0174 float _CONICAL_MIRROR_OUTER_RADIUS_ = description.constant<double>("CONICAL_MIRROR_OUTER_RADIUS");
0175 float _INNER_MIRROR_THICKNESS_ = description.constant<double>("INNER_MIRROR_THICKNESS");
0176 float _OUTER_MIRROR_THICKNESS_ = description.constant<double>("OUTER_MIRROR_THICKNESS");
0177
0178
0179 float _FIDUCIAL_VOLUME_LENGTH_ = description.constant<double>("FIDUCIAL_VOLUME_LENGTH");
0180 float _SENSOR_AREA_LENGTH_ = description.constant<double>("SENSOR_AREA_LENGTH");
0181 float _HRPPD_CENTRAL_ROW_OFFSET_ = description.constant<double>("HRPPD_CENTRAL_ROW_OFFSET");
0182 float _HRPPD_WINDOW_THICKNESS_ = description.constant<double>("HRPPD_WINDOW_THICKNESS");
0183 float _HRPPD_CONTAINER_VOLUME_HEIGHT_ =
0184 description.constant<double>("HRPPD_CONTAINER_VOLUME_HEIGHT");
0185 float _HRPPD_INSTALLATION_GAP_ = description.constant<double>("HRPPD_INSTALLATION_GAP");
0186
0187 float _HRPPD_SUPPORT_GRID_BAR_HEIGHT_ =
0188 description.constant<double>("HRPPD_SUPPORT_GRID_BAR_HEIGHT");
0189
0190 float _HRPPD_TILE_SIZE_ = description.constant<double>("HRPPD_TILE_SIZE");
0191 float _HRPPD_OPEN_AREA_SIZE_ = description.constant<double>("HRPPD_OPEN_AREA_SIZE");
0192 float _HRPPD_ACTIVE_AREA_SIZE_ = description.constant<double>("HRPPD_ACTIVE_AREA_SIZE");
0193 float _HRPPD_CERAMIC_BODY_THICKNESS_ =
0194 description.constant<double>("HRPPD_CERAMIC_BODY_THICKNESS");
0195 float _HRPPD_BASEPLATE_THICKNESS_ = description.constant<double>("HRPPD_BASEPLATE_THICKNESS");
0196 float _HRPPD_PLATING_LAYER_THICKNESS_ =
0197 description.constant<double>("HRPPD_PLATING_LAYER_THICKNESS");
0198 float _EFFECTIVE_MCP_THICKNESS_ = description.constant<double>("EFFECTIVE_MCP_THICKNESS");
0199
0200 float _READOUT_PCB_THICKNESS_ = description.constant<double>("READOUT_PCB_THICKNESS");
0201 float _READOUT_PCB_SIZE_ = description.constant<double>("READOUT_PCB_SIZE");
0202
0203 float _ASIC_SIZE_XY_ = description.constant<double>("ASIC_SIZE_XY");
0204 float _ASIC_THICKNESS_ = description.constant<double>("ASIC_THICKNESS");
0205
0206
0207 float _AEROGEL_INNER_WALL_THICKNESS_ =
0208 description.constant<double>("AEROGEL_INNER_WALL_THICKNESS");
0209 float _VESSEL_INNER_WALL_THICKNESS_ = description.constant<double>("VESSEL_INNER_WALL_THICKNESS");
0210 float _VESSEL_OUTER_WALL_THICKNESS_ = description.constant<double>("VESSEL_OUTER_WALL_THICKNESS");
0211 float _VESSEL_OUTER_RADIUS_ = description.constant<double>("VESSEL_OUTER_RADIUS");
0212 double _VESSEL_FRONT_SIDE_THICKNESS_ =
0213 description.constant<double>("VESSEL_FRONT_SIDE_THICKNESS");
0214 float _FLANGE_CLEARANCE_ = description.constant<double>("FLANGE_CLEARANCE");
0215 float _BUILDING_BLOCK_CLEARANCE_ = description.constant<double>("BUILDING_BLOCK_CLEARANCE");
0216
0217 float _AEROGEL_SEPARATOR_WALL_THICKNESS_ =
0218 description.constant<double>("AEROGEL_SEPARATOR_WALL_THICKNESS");
0219 float _AEROGEL_OUTER_WALL_THICKNESS_ =
0220 description.constant<double>("AEROGEL_OUTER_WALL_THICKNESS");
0221
0222 double m_gas_volume_length =
0223 _FIDUCIAL_VOLUME_LENGTH_ - _VESSEL_FRONT_SIDE_THICKNESS_ - _SENSOR_AREA_LENGTH_;
0224 double m_gas_volume_radius = _VESSEL_OUTER_RADIUS_ - _VESSEL_OUTER_WALL_THICKNESS_;
0225
0226
0227
0228
0229 Tube eflange(0.0, _FLANGE_EPIPE_DIAMETER_ / 2 + clearance, 25);
0230 Tube hflange(0.0, _FLANGE_HPIPE_DIAMETER_ / 2 + clearance, 25);
0231
0232 double r0 = _FLANGE_EPIPE_DIAMETER_ / 2 + clearance;
0233 double r1 = _FLANGE_HPIPE_DIAMETER_ / 2 + clearance;
0234 double L = _FLANGE_HPIPE_OFFSET_;
0235 double a = r0 * L / (r0 - r1);
0236 double b = r0 * r0 / a;
0237 double c = r1 * (a - b) / r0;
0238
0239
0240 double pDz = 25, pTheta = 0.0, pPhi = 0.0, pDy1 = (a - b - c) / 2, pDy2 = pDy1;
0241 double pDx1 = sqrt(r0 * r0 - b * b), pDx2 = pDx1 * r1 / r0, pDx3 = pDx1, pDx4 = pDx2, pAlp1 = 0.0,
0242 pAlp2 = 0.0;
0243
0244 Trap wedge(pDz, pTheta, pPhi, pDy1, pDx1, pDx2, pAlp1, pDy2, pDx3, pDx4, pAlp2);
0245
0246 UnionSolid flange_shape(eflange, hflange, Position(-_FLANGE_HPIPE_OFFSET_, 0.0, 0.0));
0247 Rotation3D rZ(RotationZYX(M_PI / 2.0, 0.0, 0.0));
0248 Transform3D transform_flange(rZ, Position(-b - pDy1, 0.0, 0.0));
0249 UnionSolid flange_final_shape(flange_shape, wedge, transform_flange);
0250
0251 Volume flangeVol(detName + "_flange", flange_final_shape, mirrorMat);
0252 flangeVol.setVisAttributes(mirrorVis);
0253
0254 SubtractionSolid pfRICH_volume_shape(pfRICH_air_volume, flange_final_shape);
0255
0256 Volume pfRICH_volume(detName + "_Vol", pfRICH_volume_shape,
0257 vesselGas);
0258
0259 pv = mother.placeVolume(pfRICH_volume, transform);
0260
0261 if (id != 0) {
0262 pv.addPhysVolID("system", id);
0263 }
0264 sdet.setPlacement(pv);
0265
0266
0267
0268 double boreDelta = vesselRmin1 - vesselRmin0;
0269 Cone vesselTank(vesselLength / 2.0, vesselRmin1, vesselRmax1, vesselRmin0, vesselRmax0);
0270 Cone gasvolTank(vesselLength / 2.0 - windowThickness, vesselRmin1 + wallThickness,
0271 vesselRmax1 - wallThickness, vesselRmin0 + wallThickness,
0272 vesselRmax0 - wallThickness);
0273
0274 Cone vesselWall(vesselLength / 2.0, vesselRmax1 - 0.1, vesselRmax1, vesselRmax0 - 0.1,
0275 vesselRmax0);
0276
0277 Box gasvolBox(1000, 1000, 1000);
0278
0279 Solid gasvolSolid;
0280 gasvolSolid = gasvolTank;
0281
0282 Solid vesselSolid;
0283 vesselSolid = vesselTank;
0284
0285 Solid mirrorSolid;
0286 mirrorSolid = mirror_cone;
0287
0288 Solid wallSolid;
0289 wallSolid = vesselWall;
0290
0291 Volume vesselVol(detName + "_vesel_vol", wallSolid, vesselMat);
0292 vesselVol.setVisAttributes(vesselVis);
0293
0294 PlacedVolume vesselPV = pfRICH_volume.placeVolume(vesselVol, Position(0, 0, 0));
0295 DetElement vesselDE(sdet, "vessel_de", 0);
0296 vesselDE.setPlacement(vesselPV);
0297
0298
0299
0300
0301 Cone aerogelSolid(aerogelThickness / 2,
0302 radiatorRmin + boreDelta * aerogelThickness / vesselLength,
0303 radiatorRmax, radiatorRmin,
0304 radiatorRmax);
0305 Cone filterSolid(filterThickness / 2,
0306 radiatorRmin + boreDelta *
0307 (aerogelThickness + airgapThickness + filterThickness) /
0308 vesselLength,
0309 radiatorRmax,
0310 radiatorRmin + boreDelta * (aerogelThickness + airgapThickness) /
0311 vesselLength,
0312 radiatorRmax);
0313 Volume aerogelVol(detName + "_aerogel", aerogelSolid, aerogelMat);
0314 Volume filterVol(detName + "_filter", filterSolid, filterMat);
0315
0316
0317 description.add(Constant("PFRICH_aerogel_material", aerogelMat.ptr()->GetName(), "string"));
0318 description.add(Constant("PFRICH_filter_material", filterMat.ptr()->GetName(), "string"));
0319 description.add(Constant("PFRICH_gasvol_material", gasvolMat.ptr()->GetName(), "string"));
0320
0321 Box sensorSolid(sensorSide / 2., sensorSide / 2., sensorThickness / 2.);
0322 Volume sensorVol(detName + "_sensor", sensorSolid, sensorMat);
0323 sensorVol.setVisAttributes(sensorVis);
0324
0325
0326
0327
0328
0329 Volume mirrorVol(detName, mirrorSolid, mirrorMat);
0330 mirrorVol.setVisAttributes(mirrorVis);
0331
0332 double xysize = _HRPPD_TILE_SIZE_, wndthick = _HRPPD_WINDOW_THICKNESS_;
0333
0334
0335 double hrppd_container_volume_thickness = _HRPPD_CONTAINER_VOLUME_HEIGHT_;
0336
0337 double _ACRYLIC_THICKNESS_ = 0.3;
0338
0339
0340
0341
0342 Box hrppd_Solid(xysize / 2, xysize / 2, hrppd_container_volume_thickness / 2);
0343
0344 Volume hrppdVol_air(detName + "_air_hrppd", hrppd_Solid, air);
0345
0346 hrppdVol_air.setSensitiveDetector(sens);
0347 hrppdVol_air.setVisAttributes(gasvolVis);
0348
0349
0350 Box wnd_Solid(xysize / 2, xysize / 2, wndthick / 2);
0351
0352 Volume wndVol(detName + "_wnd", wnd_Solid, HRPPD_WindowMat);
0353 wndVol.setVisAttributes(gasvolVis);
0354
0355 double accu = -hrppd_container_volume_thickness / 2;
0356
0357 PlacedVolume wndPV = hrppdVol_air.placeVolume(wndVol, Position(0, 0, accu + wndthick / 2));
0358
0359 DetElement wndDE(sdet, "wnd_de", 0);
0360 wndDE.setPlacement(wndPV);
0361
0362
0363 double xyactive = _HRPPD_ACTIVE_AREA_SIZE_;
0364 double xyopen = _HRPPD_OPEN_AREA_SIZE_;
0365 double certhick = _HRPPD_CERAMIC_BODY_THICKNESS_;
0366
0367 accu += wndthick;
0368
0369
0370 Box cerbox(xysize / 2, xysize / 2, certhick / 2);
0371 Box cut_box(xyopen / 2, xyopen / 2, certhick / 2);
0372
0373 SubtractionSolid ceramic(cerbox, cut_box, Position(0, 0, -_HRPPD_BASEPLATE_THICKNESS_));
0374
0375 Volume ceramicVol(detName + "_ceramic", ceramic, HRPPD_MPDMat);
0376 ceramicVol.setVisAttributes(gasvolVis);
0377
0378 PlacedVolume ceramicPV =
0379 hrppdVol_air.placeVolume(ceramicVol, Position(0.0, 0.0, accu + certhick / 2));
0380 DetElement ceramicDE(sdet, "ceramic_de", 0);
0381 ceramicDE.setPlacement(ceramicPV);
0382
0383
0384
0385 Box plating_solid(xyopen / 2, xyopen / 2, _HRPPD_PLATING_LAYER_THICKNESS_ / 2);
0386 Volume platingVol(detName + "_plating", plating_solid, HRPPD_MPDMat);
0387
0388 platingVol.setVisAttributes(gasvolVis);
0389 PlacedVolume platingPV =
0390 hrppdVol_air.placeVolume(platingVol, Position(0.0, 0.0, accu + certhick / 2));
0391 DetElement platingDE(sdet, "plating_de", 0);
0392 platingDE.setPlacement(platingPV);
0393
0394
0395
0396 Box mcp_solid(xyopen / 2, xyopen / 2, _EFFECTIVE_MCP_THICKNESS_ / 2);
0397 Volume mcpVol(detName + "_mcp", mcp_solid, HRPPD_MPDMat);
0398
0399 mcpVol.setVisAttributes(gasvolVis);
0400 PlacedVolume mcpPV = hrppdVol_air.placeVolume(
0401 mcpVol, Position(0.0, 0.0,
0402 accu + certhick / 2 + _HRPPD_PLATING_LAYER_THICKNESS_ / 2 +
0403 _EFFECTIVE_MCP_THICKNESS_ / 2));
0404 DetElement mcpDE(sdet, "mcp_de", 0);
0405 mcpDE.setPlacement(mcpPV);
0406
0407 double pdthick = 0.001;
0408
0409 Box pdbox_solid(xyactive / 2, xyactive / 2, pdthick / 2);
0410 Volume pdboxVol(detName + "_pd", pdbox_solid, HRPPD_MPDMat);
0411
0412 pdboxVol.setVisAttributes(gasvolVis);
0413 PlacedVolume pdboxPV =
0414 hrppdVol_air.placeVolume(pdboxVol, Position(0.0, 0.0, accu + pdthick + pdthick / 2));
0415
0416 DetElement pdboxDE(sdet, "pdbox_de", 0);
0417 pdboxDE.setPlacement(pdboxPV);
0418
0419 Box qdbox_solid(xyactive / 2, xyactive / 2, pdthick / 2);
0420 Volume qdboxVol(detName + "_qd", qdbox_solid, HRPPD_MPDMat);
0421
0422 qdboxVol.setVisAttributes(gasvolVis);
0423 PlacedVolume qdboxPV = hrppdVol_air.placeVolume(qdboxVol, Position(0.0, 0.0, accu + pdthick / 2));
0424
0425 DetElement qdboxDE(sdet, "qdbox_de", 0);
0426 qdboxDE.setPlacement(qdboxPV);
0427
0428 accu += certhick + 1 * mm;
0429
0430
0431
0432 Box pcb_solid(_READOUT_PCB_SIZE_ / 2, _READOUT_PCB_SIZE_ / 2, _READOUT_PCB_THICKNESS_ / 2);
0433 Volume pcbVol(detName + "_pcb", pcb_solid, HRPPD_PCBMat);
0434
0435 pcbVol.setVisAttributes(gasvolVis);
0436 PlacedVolume pcbPV =
0437 hrppdVol_air.placeVolume(pcbVol, Position(0.0, 0.0, accu + _READOUT_PCB_THICKNESS_ / 2));
0438
0439 DetElement pcbDE(sdet, "pcb_de", 0);
0440 pcbDE.setPlacement(pcbPV);
0441
0442 accu += _READOUT_PCB_THICKNESS_ + 0.001;
0443
0444
0445
0446 Box asic_solid(_ASIC_SIZE_XY_ / 2, _ASIC_SIZE_XY_ / 2, _ASIC_THICKNESS_ / 2);
0447 Volume asicVol(detName + "_asic", asic_solid, HRPPD_ASICMat);
0448 asicVol.setVisAttributes(mirrorVis);
0449
0450 double asic_pitch = _READOUT_PCB_SIZE_ / 2;
0451
0452 imod = 0;
0453
0454 for (unsigned ix = 0; ix < 2; ix++) {
0455 double xOffset = asic_pitch * (ix - (2 - 1) / 2.);
0456
0457 for (unsigned iy = 0; iy < 2; iy++) {
0458 double yOffset = asic_pitch * (iy - (2 - 1) / 2.);
0459
0460 auto asicPV = hrppdVol_air.placeVolume(
0461 asicVol, Position(xOffset, yOffset, accu + _ASIC_THICKNESS_ / 2));
0462
0463 DetElement asicDE(sdet, "asic_de_" + std::to_string(imod), 0);
0464 asicDE.setPlacement(asicPV);
0465
0466 imod++;
0467
0468 }
0469 }
0470
0471 accu += _ASIC_THICKNESS_ + 0.01 * mm;
0472
0473
0474
0475 unsigned const hdim = 9;
0476 const unsigned flags[hdim][hdim] = {
0477
0478 {0, 0, 1, 1, 1, 1, 1, 0, 0}, {0, 1, 1, 1, 1, 1, 1, 1, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1},
0479 {1, 1, 1, 1, 2, 1, 1, 1, 1}, {3, 3, 3, 4, 0, 2, 1, 1, 1}, {1, 1, 1, 1, 2, 1, 1, 1, 1},
0480 {1, 1, 1, 1, 1, 1, 1, 1, 1}, {0, 1, 1, 1, 1, 1, 1, 1, 0}, {0, 0, 1, 1, 1, 1, 1, 0, 0}};
0481
0482 std::vector<std::pair<TVector2, bool>> coord;
0483
0484 for (unsigned ix = 0; ix < hdim; ix++) {
0485 double xOffset = (_HRPPD_TILE_SIZE_ + _HRPPD_INSTALLATION_GAP_) * (ix - (hdim - 1) / 2.);
0486
0487 for (unsigned iy = 0; iy < hdim; iy++) {
0488 double yOffset = (_HRPPD_TILE_SIZE_ + _HRPPD_INSTALLATION_GAP_) * (iy - (hdim - 1) / 2.);
0489 unsigned flag = flags[hdim - iy - 1][ix];
0490
0491 if (!flag)
0492 continue;
0493
0494 double qxOffset = xOffset + (flag >= 3 ? -_HRPPD_CENTRAL_ROW_OFFSET_ : 0.0);
0495 coord.push_back(std::make_pair(TVector2(qxOffset, yOffset), flag % 2));
0496 }
0497 }
0498
0499
0500
0501 for (auto xyptr : coord) {
0502 auto& xy = xyptr.first;
0503
0504 double sx = xy.X();
0505 double sy = xy.Y();
0506
0507
0508 auto sensorPlacement =
0509 Transform3D(Translation3D(sensorPlanePos.x(), sensorPlanePos.y(),
0510 sensorPlanePos.z() + 34) *
0511 Translation3D(sx, sy, 0.)
0512 );
0513
0514 auto sensorPV = pfRICH_volume.placeVolume(hrppdVol_air, sensorPlacement);
0515
0516
0517 sensorPV.addPhysVolID("module", imod);
0518 auto imodEnc = encodeSensorID(sensorPV.volIDs());
0519 DetElement sensorDE(sdet, "sensor_de_" + std::to_string(imod), imodEnc);
0520 sensorDE.setPlacement(sensorPV);
0521 if (!debug_optics) {
0522 SkinSurface sensorSkin(description, sensorDE,
0523 "sensor_optical_surface_" + std::to_string(imod), sensorSurf,
0524 sensorVol);
0525 sensorSkin.isValid();
0526 };
0527
0528
0529 imod++;
0530 }
0531
0532
0533
0534 const int _AEROGEL_BAND_COUNT_ = 3;
0535 float m_r0min = _FLANGE_EPIPE_DIAMETER_ / 2 + _FLANGE_CLEARANCE_ + _VESSEL_INNER_WALL_THICKNESS_ +
0536 _BUILDING_BLOCK_CLEARANCE_;
0537 float m_r0max = m_gas_volume_radius - _BUILDING_BLOCK_CLEARANCE_;
0538
0539 const unsigned adim[_AEROGEL_BAND_COUNT_] = {9, 14, 20};
0540 double rheight =
0541 (m_r0max - m_r0min - (_AEROGEL_BAND_COUNT_ - 1) * _AEROGEL_SEPARATOR_WALL_THICKNESS_ -
0542 _AEROGEL_INNER_WALL_THICKNESS_ - _AEROGEL_OUTER_WALL_THICKNESS_) /
0543 _AEROGEL_BAND_COUNT_;
0544
0545 double agthick = 2.5;
0546
0547 double m_gzOffset = m_gas_volume_length / 2 + _BUILDING_BLOCK_CLEARANCE_ + agthick / 2;
0548
0549 string aerogel_name = "a1040";
0550
0551 int kkcounter = 0;
0552
0553 for (unsigned ir = 0; ir < _AEROGEL_BAND_COUNT_; ir++) {
0554 int counter = ir ? -1 : 0;
0555 double apitch = 360 * degree / adim[ir];
0556 double aerogel_r0 = m_r0min + _AEROGEL_INNER_WALL_THICKNESS_ +
0557 ir * (_AEROGEL_SEPARATOR_WALL_THICKNESS_ + rheight);
0558 double aerogel_r1 = aerogel_r0 + rheight;
0559 double rm = (aerogel_r0 + aerogel_r1) / 2;
0560
0561
0562
0563
0564
0565 double l0 = 2 * M_PI * rm / adim[ir];
0566 double l1 = _AEROGEL_SEPARATOR_WALL_THICKNESS_;
0567 double lsum = l0 + l1;
0568
0569
0570 double wd0 = (l0 / lsum) * (360 * degree / adim[ir]);
0571 double wd1 = (l1 / lsum) * (360 * degree / adim[ir]);
0572 TString ag_name = "Tmp", sp_name = "Tmp";
0573
0574 if (ir)
0575 ag_name.Form("%s-%d-00", aerogel_name.c_str(), ir);
0576 if (ir)
0577 sp_name.Form("A-Spacer--%d-00", ir);
0578
0579 Tube agtube(aerogel_r0, aerogel_r1, agthick / 2, 0 * degree, wd0);
0580 Tube sptube(aerogel_r0, aerogel_r1, agthick / 2, wd0, wd0 + wd1);
0581
0582 for (unsigned ia = 0; ia < adim[ir]; ia++) {
0583
0584 Rotation3D r_aerogel_Z(RotationZYX(ia * apitch, 0.0, 0.0));
0585 Rotation3D r_aerogel_Zinv(RotationZYX(-1. * ia * apitch, 0.0, 0.0));
0586
0587 if (ir) {
0588 ag_name.Form("%s-%d-%02d", "aerogel", ir, ia);
0589
0590 Volume agtubeVol(ag_name.Data(), agtube, gasvolMat);
0591 auto aerogelTilePlacement = Transform3D(r_aerogel_Z, Position(0.0, 0.0, -m_gzOffset));
0592 auto aerogelTilePV = pfRICH_volume.placeVolume(agtubeVol, aerogelTilePlacement);
0593 DetElement aerogelDE(sdet, "aerogel_de_" + std::to_string(kkcounter), 0);
0594 aerogelDE.setPlacement(aerogelTilePV);
0595
0596 Volume sptubeVol(detName + "_sptube", sptube, mirrorMat);
0597 auto sptubePlacement = Transform3D(r_aerogel_Z, Position(0.0, 0.0, -m_gzOffset));
0598 auto sptubePV = pfRICH_volume.placeVolume(sptubeVol, sptubePlacement);
0599 DetElement sptubeDE(sdet, "sptube_de_" + std::to_string(kkcounter), 0);
0600 sptubeDE.setPlacement(sptubePV);
0601
0602 } else {
0603
0604 ag_name.Form("%s-%d-%02d", "aerogel_inner", ir, ia);
0605
0606 Tube agtube_inner(aerogel_r0, aerogel_r1, agthick / 2, 0 * degree + ia * apitch,
0607 wd0 + ia * apitch);
0608 SubtractionSolid agsub(agtube_inner, flange_final_shape);
0609 Volume agsubtubeVol(ag_name.Data(), agsub, gasvolMat);
0610 auto aerogelTilePlacement =
0611 Transform3D(RotationZYX(0.0, 0.0, 0.0), Position(0.0, 0.0, -m_gzOffset));
0612 auto agsubTilePV = pfRICH_volume.placeVolume(agsubtubeVol, aerogelTilePlacement);
0613
0614 DetElement aerogelDE(sdet, "agsubTile_de_" + std::to_string(counter), 0);
0615 aerogelDE.setPlacement(agsubTilePV);
0616
0617 sp_name.Form("%s-%d-%02d", "sp_inner", ir, ia);
0618 Tube sptube_inner(aerogel_r0, aerogel_r1, agthick / 2, wd0 + ia * apitch,
0619 wd0 + wd1 + ia * apitch);
0620
0621 SubtractionSolid spsub(sptube_inner, flange_final_shape);
0622 Volume spsubtubeVol(sp_name.Data(), spsub, mirrorMat);
0623 auto spTilePlacement =
0624 Transform3D(RotationZYX(0.0, 0.0, 0.0), Position(0.0, 0.0, -m_gzOffset));
0625 auto spsubTilePV = pfRICH_volume.placeVolume(spsubtubeVol, spTilePlacement);
0626
0627 DetElement sptubeTileDE(sdet, "sptubeTile_de_" + std::to_string(counter), 0);
0628 sptubeTileDE.setPlacement(spsubTilePV);
0629
0630 sp_name.Form("A-Spacer--%d-%02d", ir, ia);
0631
0632 }
0633
0634 counter++;
0635 kkcounter++;
0636
0637 }
0638 }
0639
0640
0641
0642 double sp_accu = m_r0min;
0643 int tube_counter = 0;
0644
0645 for (unsigned ir = 0; ir < _AEROGEL_BAND_COUNT_ + 1; ir++) {
0646 double thickness = ir ? (ir == _AEROGEL_BAND_COUNT_ ? _AEROGEL_OUTER_WALL_THICKNESS_
0647 : _AEROGEL_SEPARATOR_WALL_THICKNESS_)
0648 : _AEROGEL_INNER_WALL_THICKNESS_;
0649 double sp_r0 = sp_accu;
0650 double sp_r1 = sp_r0 + thickness;
0651
0652 TString sp_name = "Tmp";
0653 if (ir)
0654 sp_name.Form("R-Spacer--%d-00", ir);
0655
0656 Tube sptube(sp_r0, sp_r1, agthick / 2, 0 * degree, 360 * degree);
0657 Volume sptubeVol(detName + "_radial_sptube", sptube, sensorMat);
0658 auto sptubePlacement = Transform3D(RotationZYX(0.0, 0.0, 0.0), Position(0.0, 0.0, -m_gzOffset));
0659
0660 if (ir) {
0661
0662 auto sptubePV = pfRICH_volume.placeVolume(sptubeVol, sptubePlacement);
0663
0664 DetElement sptubeDE(sdet, "sptube_de_" + std::to_string(tube_counter), 0);
0665 sptubeDE.setPlacement(sptubePV);
0666
0667 }
0668
0669 else {
0670
0671 SubtractionSolid spsub(sptube, flange_final_shape);
0672 Volume agsubtubeVol(detName + "_radial_sptube_inner", spsub, gasvolMat);
0673
0674 auto sptubePV = pfRICH_volume.placeVolume(agsubtubeVol, sptubePlacement);
0675
0676 DetElement sptubeDE(sdet, "sptube_de_" + std::to_string(tube_counter), 0);
0677 sptubeDE.setPlacement(sptubePV);
0678
0679 }
0680
0681 sp_accu += thickness + rheight;
0682
0683 tube_counter++;
0684
0685 }
0686
0687
0688
0689 double mlen = m_gas_volume_length - _BUILDING_BLOCK_CLEARANCE_;
0690
0691 mlen -= _BUILDING_BLOCK_CLEARANCE_ + _HRPPD_SUPPORT_GRID_BAR_HEIGHT_;
0692
0693 double mirror_r0[2] = {m_r0min, m_r0max};
0694 double mirror_r1[2] = {_CONICAL_MIRROR_INNER_RADIUS_, _CONICAL_MIRROR_OUTER_RADIUS_};
0695
0696 for (unsigned im = 0; im < 2; im++) {
0697
0698 double mirror_thickness = im ? _OUTER_MIRROR_THICKNESS_ : _INNER_MIRROR_THICKNESS_;
0699
0700 if (im) {
0701
0702 Cone mirror_outer_cone_shape(mlen / 2.0, mirror_r0[im], mirror_r0[im] + mirror_thickness,
0703 mirror_r1[im], mirror_r1[im] + mirror_thickness);
0704
0705 Volume outer_mirrorVol(detName + "_outer_mirror", mirror_outer_cone_shape, mirrorMat);
0706
0707 PlacedVolume mirror_outerPV = pfRICH_volume.placeVolume(outer_mirrorVol, Position(0, 0, 0));
0708
0709 DetElement mirror_outerDE(sdet, "_outer_mirror_de", 0);
0710 mirror_outerDE.setPlacement(mirror_outerPV);
0711
0712 } else {
0713
0714 Cone mirror_inner_cone_shape(mlen / 2., mirror_r0[im], mirror_r0[im] + mirror_thickness,
0715 mirror_r1[im], mirror_r1[im] + mirror_thickness);
0716
0717 SubtractionSolid mirror_inner_sub(mirror_inner_cone_shape, flange_final_shape);
0718
0719 Volume inner_mirrorVol(detName + "_inner_mirror", mirror_inner_sub, mirrorMat);
0720
0721 PlacedVolume mirror_innerPV = pfRICH_volume.placeVolume(inner_mirrorVol, Position(0, 0, 0));
0722
0723 DetElement mirror_innerDE(sdet, "_inner_mirror_de", 0);
0724 mirror_innerDE.setPlacement(mirror_innerPV);
0725 }
0726
0727 }
0728
0729
0730
0731 double acthick = _ACRYLIC_THICKNESS_;
0732
0733
0734 Tube ac_tube(m_r0min + 3, m_r0max - 1, acthick / 2, 0 * degree, 360 * degree);
0735 SubtractionSolid ac_shape(ac_tube, flange_final_shape);
0736
0737 Volume acVol(detName + "_ac", ac_shape, gasvolMat);
0738
0739 PlacedVolume ac_PV = pfRICH_volume.placeVolume(acVol, Position(0, 0, -21.3));
0740
0741 DetElement acDE(sdet, "ac_de", 0);
0742 acDE.setPlacement(ac_PV);
0743
0744 return sdet;
0745 }
0746
0747
0748 DECLARE_DETELEMENT(epic_PFRICH, createDetector)