File indexing completed on 2025-01-18 09:15:59
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 DetElement hrppdDE(sdet, "hrppd_de", 0);
0349
0350
0351 Box wnd_Solid(xysize / 2, xysize / 2, wndthick / 2);
0352
0353 Volume wndVol(detName + "_wnd", wnd_Solid, HRPPD_WindowMat);
0354 wndVol.setVisAttributes(gasvolVis);
0355
0356 double accu = -hrppd_container_volume_thickness / 2;
0357
0358 PlacedVolume wndPV = hrppdVol_air.placeVolume(wndVol, Position(0, 0, accu + wndthick / 2));
0359
0360 DetElement wndDE(hrppdDE, "wnd_de", 0);
0361 wndDE.setPlacement(wndPV);
0362
0363
0364 double xyactive = _HRPPD_ACTIVE_AREA_SIZE_;
0365 double xyopen = _HRPPD_OPEN_AREA_SIZE_;
0366 double certhick = _HRPPD_CERAMIC_BODY_THICKNESS_;
0367
0368 accu += wndthick;
0369
0370
0371 Box cerbox(xysize / 2, xysize / 2, certhick / 2);
0372 Box cut_box(xyopen / 2, xyopen / 2, certhick / 2);
0373
0374 SubtractionSolid ceramic(cerbox, cut_box, Position(0, 0, -_HRPPD_BASEPLATE_THICKNESS_));
0375
0376 Volume ceramicVol(detName + "_ceramic", ceramic, HRPPD_MPDMat);
0377 ceramicVol.setVisAttributes(gasvolVis);
0378
0379 PlacedVolume ceramicPV =
0380 hrppdVol_air.placeVolume(ceramicVol, Position(0.0, 0.0, accu + certhick / 2));
0381 DetElement ceramicDE(sdet, "ceramic_de", 0);
0382 ceramicDE.setPlacement(ceramicPV);
0383
0384
0385
0386 Box plating_solid(xyopen / 2, xyopen / 2, _HRPPD_PLATING_LAYER_THICKNESS_ / 2);
0387 Volume platingVol(detName + "_plating", plating_solid, HRPPD_MPDMat);
0388
0389 platingVol.setVisAttributes(gasvolVis);
0390 PlacedVolume platingPV =
0391 hrppdVol_air.placeVolume(platingVol, Position(0.0, 0.0, accu + certhick / 2));
0392 DetElement platingDE(sdet, "plating_de", 0);
0393 platingDE.setPlacement(platingPV);
0394
0395
0396
0397 Box mcp_solid(xyopen / 2, xyopen / 2, _EFFECTIVE_MCP_THICKNESS_ / 2);
0398 Volume mcpVol(detName + "_mcp", mcp_solid, HRPPD_MPDMat);
0399
0400 mcpVol.setVisAttributes(gasvolVis);
0401 PlacedVolume mcpPV = hrppdVol_air.placeVolume(
0402 mcpVol, Position(0.0, 0.0,
0403 accu + certhick / 2 + _HRPPD_PLATING_LAYER_THICKNESS_ / 2 +
0404 _EFFECTIVE_MCP_THICKNESS_ / 2));
0405 DetElement mcpDE(sdet, "mcp_de", 0);
0406 mcpDE.setPlacement(mcpPV);
0407
0408 double pdthick = 0.001;
0409
0410 Box pdbox_solid(xyactive / 2, xyactive / 2, pdthick / 2);
0411 Volume pdboxVol(detName + "_pd", pdbox_solid, HRPPD_MPDMat);
0412
0413 pdboxVol.setVisAttributes(gasvolVis);
0414 PlacedVolume pdboxPV =
0415 hrppdVol_air.placeVolume(pdboxVol, Position(0.0, 0.0, accu + pdthick + pdthick / 2));
0416
0417 DetElement pdboxDE(sdet, "pdbox_de", 0);
0418 pdboxDE.setPlacement(pdboxPV);
0419
0420 Box qdbox_solid(xyactive / 2, xyactive / 2, pdthick / 2);
0421 Volume qdboxVol(detName + "_qd", qdbox_solid, HRPPD_MPDMat);
0422
0423 qdboxVol.setVisAttributes(gasvolVis);
0424 PlacedVolume qdboxPV = hrppdVol_air.placeVolume(qdboxVol, Position(0.0, 0.0, accu + pdthick / 2));
0425
0426 DetElement qdboxDE(sdet, "qdbox_de", 0);
0427 pdboxDE.setPlacement(qdboxPV);
0428
0429 accu += certhick + 1 * mm;
0430
0431
0432
0433 Box pcb_solid(_READOUT_PCB_SIZE_ / 2, _READOUT_PCB_SIZE_ / 2, _READOUT_PCB_THICKNESS_ / 2);
0434 Volume pcbVol(detName + "_pcb", pcb_solid, HRPPD_PCBMat);
0435
0436 pcbVol.setVisAttributes(gasvolVis);
0437 PlacedVolume pcbPV =
0438 hrppdVol_air.placeVolume(pcbVol, Position(0.0, 0.0, accu + _READOUT_PCB_THICKNESS_ / 2));
0439
0440 DetElement pcbDE(sdet, "pcb_de", 0);
0441 pcbDE.setPlacement(pcbPV);
0442
0443 accu += _READOUT_PCB_THICKNESS_ + 0.001;
0444
0445
0446
0447 Box asic_solid(_ASIC_SIZE_XY_ / 2, _ASIC_SIZE_XY_ / 2, _ASIC_THICKNESS_ / 2);
0448 Volume asicVol(detName + "_asic", asic_solid, HRPPD_ASICMat);
0449 asicVol.setVisAttributes(mirrorVis);
0450
0451 double asic_pitch = _READOUT_PCB_SIZE_ / 2;
0452
0453 imod = 0;
0454
0455 for (unsigned ix = 0; ix < 2; ix++) {
0456 double xOffset = asic_pitch * (ix - (2 - 1) / 2.);
0457
0458 for (unsigned iy = 0; iy < 2; iy++) {
0459 double yOffset = asic_pitch * (iy - (2 - 1) / 2.);
0460
0461 auto asicPV = hrppdVol_air.placeVolume(
0462 asicVol, Position(xOffset, yOffset, accu + _ASIC_THICKNESS_ / 2));
0463
0464 DetElement asicDE(sdet, "asic_de_" + std::to_string(imod), 0);
0465 asicDE.setPlacement(asicPV);
0466
0467 imod++;
0468
0469 }
0470 }
0471
0472 accu += _ASIC_THICKNESS_ + 0.01 * mm;
0473
0474
0475
0476 unsigned const hdim = 9;
0477 const unsigned flags[hdim][hdim] = {
0478
0479 {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},
0480 {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},
0481 {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}};
0482
0483 std::vector<std::pair<TVector2, bool>> coord;
0484
0485 for (unsigned ix = 0; ix < hdim; ix++) {
0486 double xOffset = (_HRPPD_TILE_SIZE_ + _HRPPD_INSTALLATION_GAP_) * (ix - (hdim - 1) / 2.);
0487
0488 for (unsigned iy = 0; iy < hdim; iy++) {
0489 double yOffset = (_HRPPD_TILE_SIZE_ + _HRPPD_INSTALLATION_GAP_) * (iy - (hdim - 1) / 2.);
0490 unsigned flag = flags[hdim - iy - 1][ix];
0491
0492 if (!flag)
0493 continue;
0494
0495 double qxOffset = xOffset + (flag >= 3 ? -_HRPPD_CENTRAL_ROW_OFFSET_ : 0.0);
0496 coord.push_back(std::make_pair(TVector2(qxOffset, yOffset), flag % 2));
0497 }
0498 }
0499
0500
0501
0502 for (auto xyptr : coord) {
0503 auto& xy = xyptr.first;
0504
0505 double sx = xy.X();
0506 double sy = xy.Y();
0507
0508
0509 auto sensorPlacement =
0510 Transform3D(Translation3D(sensorPlanePos.x(), sensorPlanePos.y(),
0511 sensorPlanePos.z() + 34) *
0512 Translation3D(sx, sy, 0.)
0513 );
0514
0515 auto sensorPV = pfRICH_volume.placeVolume(hrppdVol_air, sensorPlacement);
0516
0517
0518 sensorPV.addPhysVolID("module", imod);
0519 auto imodEnc = encodeSensorID(sensorPV.volIDs());
0520 DetElement sensorDE(sdet, "sensor_de_" + std::to_string(imod), imodEnc);
0521 sensorDE.setPlacement(sensorPV);
0522 if (!debug_optics) {
0523 SkinSurface sensorSkin(description, sensorDE,
0524 "sensor_optical_surface_" + std::to_string(imod), sensorSurf,
0525 sensorVol);
0526 sensorSkin.isValid();
0527 };
0528
0529
0530 imod++;
0531 }
0532
0533
0534
0535 const int _AEROGEL_BAND_COUNT_ = 3;
0536 float m_r0min = _FLANGE_EPIPE_DIAMETER_ / 2 + _FLANGE_CLEARANCE_ + _VESSEL_INNER_WALL_THICKNESS_ +
0537 _BUILDING_BLOCK_CLEARANCE_;
0538 float m_r0max = m_gas_volume_radius - _BUILDING_BLOCK_CLEARANCE_;
0539
0540 const unsigned adim[_AEROGEL_BAND_COUNT_] = {9, 14, 20};
0541 double rheight =
0542 (m_r0max - m_r0min - (_AEROGEL_BAND_COUNT_ - 1) * _AEROGEL_SEPARATOR_WALL_THICKNESS_ -
0543 _AEROGEL_INNER_WALL_THICKNESS_ - _AEROGEL_OUTER_WALL_THICKNESS_) /
0544 _AEROGEL_BAND_COUNT_;
0545
0546 double agthick = 2.5;
0547
0548 double m_gzOffset = m_gas_volume_length / 2 + _BUILDING_BLOCK_CLEARANCE_ + agthick / 2;
0549
0550 string aerogel_name = "a1040";
0551
0552 int kkcounter = 0;
0553
0554 for (unsigned ir = 0; ir < _AEROGEL_BAND_COUNT_; ir++) {
0555 int counter = ir ? -1 : 0;
0556 double apitch = 360 * degree / adim[ir];
0557 double aerogel_r0 = m_r0min + _AEROGEL_INNER_WALL_THICKNESS_ +
0558 ir * (_AEROGEL_SEPARATOR_WALL_THICKNESS_ + rheight);
0559 double aerogel_r1 = aerogel_r0 + rheight;
0560 double rm = (aerogel_r0 + aerogel_r1) / 2;
0561
0562
0563
0564
0565
0566 double l0 = 2 * M_PI * rm / adim[ir];
0567 double l1 = _AEROGEL_SEPARATOR_WALL_THICKNESS_;
0568 double lsum = l0 + l1;
0569
0570
0571 double wd0 = (l0 / lsum) * (360 * degree / adim[ir]);
0572 double wd1 = (l1 / lsum) * (360 * degree / adim[ir]);
0573 TString ag_name = "Tmp", sp_name = "Tmp";
0574
0575 if (ir)
0576 ag_name.Form("%s-%d-00", aerogel_name.c_str(), ir);
0577 if (ir)
0578 sp_name.Form("A-Spacer--%d-00", ir);
0579
0580 Tube agtube(aerogel_r0, aerogel_r1, agthick / 2, 0 * degree, wd0);
0581 Tube sptube(aerogel_r0, aerogel_r1, agthick / 2, wd0, wd0 + wd1);
0582
0583 for (unsigned ia = 0; ia < adim[ir]; ia++) {
0584
0585 Rotation3D r_aerogel_Z(RotationZYX(ia * apitch, 0.0, 0.0));
0586 Rotation3D r_aerogel_Zinv(RotationZYX(-1. * ia * apitch, 0.0, 0.0));
0587
0588 if (ir) {
0589 ag_name.Form("%s-%d-%02d", "aerogel", ir, ia);
0590
0591 Volume agtubeVol(ag_name.Data(), agtube, gasvolMat);
0592 auto aerogelTilePlacement = Transform3D(r_aerogel_Z, Position(0.0, 0.0, -m_gzOffset));
0593 auto aerogelTilePV = pfRICH_volume.placeVolume(agtubeVol, aerogelTilePlacement);
0594 DetElement aerogelDE(sdet, "aerogel_de_" + std::to_string(kkcounter), 0);
0595 aerogelDE.setPlacement(aerogelTilePV);
0596
0597 Volume sptubeVol(detName + "_sptube", sptube, mirrorMat);
0598 auto sptubePlacement = Transform3D(r_aerogel_Z, Position(0.0, 0.0, -m_gzOffset));
0599 auto sptubePV = pfRICH_volume.placeVolume(sptubeVol, sptubePlacement);
0600 DetElement sptubeDE(sdet, "sptube_de_" + std::to_string(kkcounter), 0);
0601 sptubeDE.setPlacement(sptubePV);
0602
0603 } else {
0604
0605 ag_name.Form("%s-%d-%02d", "aerogel_inner", ir, ia);
0606
0607 Tube agtube_inner(aerogel_r0, aerogel_r1, agthick / 2, 0 * degree + ia * apitch,
0608 wd0 + ia * apitch);
0609 SubtractionSolid agsub(agtube_inner, flange_final_shape);
0610 Volume agsubtubeVol(ag_name.Data(), agsub, gasvolMat);
0611 auto aerogelTilePlacement =
0612 Transform3D(RotationZYX(0.0, 0.0, 0.0), Position(0.0, 0.0, -m_gzOffset));
0613 auto agsubTilePV = pfRICH_volume.placeVolume(agsubtubeVol, aerogelTilePlacement);
0614
0615 DetElement aerogelDE(sdet, "agsubTile_de_" + std::to_string(counter), 0);
0616 aerogelDE.setPlacement(agsubTilePV);
0617
0618 sp_name.Form("%s-%d-%02d", "sp_inner", ir, ia);
0619 Tube sptube_inner(aerogel_r0, aerogel_r1, agthick / 2, wd0 + ia * apitch,
0620 wd0 + wd1 + ia * apitch);
0621
0622 SubtractionSolid spsub(sptube_inner, flange_final_shape);
0623 Volume spsubtubeVol(sp_name.Data(), spsub, mirrorMat);
0624 auto spTilePlacement =
0625 Transform3D(RotationZYX(0.0, 0.0, 0.0), Position(0.0, 0.0, -m_gzOffset));
0626 auto spsubTilePV = pfRICH_volume.placeVolume(spsubtubeVol, spTilePlacement);
0627
0628 DetElement sptubeTileDE(sdet, "sptubeTile_de_" + std::to_string(counter), 0);
0629 sptubeTileDE.setPlacement(spsubTilePV);
0630
0631 sp_name.Form("A-Spacer--%d-%02d", ir, ia);
0632
0633 }
0634
0635 counter++;
0636 kkcounter++;
0637
0638 }
0639 }
0640
0641
0642
0643 double sp_accu = m_r0min;
0644 int tube_counter = 0;
0645
0646 for (unsigned ir = 0; ir < _AEROGEL_BAND_COUNT_ + 1; ir++) {
0647 double thickness = ir ? (ir == _AEROGEL_BAND_COUNT_ ? _AEROGEL_OUTER_WALL_THICKNESS_
0648 : _AEROGEL_SEPARATOR_WALL_THICKNESS_)
0649 : _AEROGEL_INNER_WALL_THICKNESS_;
0650 double sp_r0 = sp_accu;
0651 double sp_r1 = sp_r0 + thickness;
0652
0653 TString sp_name = "Tmp";
0654 if (ir)
0655 sp_name.Form("R-Spacer--%d-00", ir);
0656
0657 Tube sptube(sp_r0, sp_r1, agthick / 2, 0 * degree, 360 * degree);
0658 Volume sptubeVol(detName + "_radial_sptube", sptube, sensorMat);
0659 auto sptubePlacement = Transform3D(RotationZYX(0.0, 0.0, 0.0), Position(0.0, 0.0, -m_gzOffset));
0660
0661 if (ir) {
0662
0663 auto sptubePV = pfRICH_volume.placeVolume(sptubeVol, sptubePlacement);
0664
0665 DetElement sptubeDE(sdet, "sptube_de_" + std::to_string(tube_counter), 0);
0666 sptubeDE.setPlacement(sptubePV);
0667
0668 }
0669
0670 else {
0671
0672 SubtractionSolid spsub(sptube, flange_final_shape);
0673 Volume agsubtubeVol(detName + "_radial_sptube_inner", spsub, gasvolMat);
0674
0675 auto sptubePV = pfRICH_volume.placeVolume(agsubtubeVol, sptubePlacement);
0676
0677 DetElement sptubeDE(sdet, "sptube_de_" + std::to_string(tube_counter), 0);
0678 sptubeDE.setPlacement(sptubePV);
0679
0680 }
0681
0682 sp_accu += thickness + rheight;
0683
0684 tube_counter++;
0685
0686 }
0687
0688
0689
0690 double mlen = m_gas_volume_length - _BUILDING_BLOCK_CLEARANCE_;
0691
0692 mlen -= _BUILDING_BLOCK_CLEARANCE_ + _HRPPD_SUPPORT_GRID_BAR_HEIGHT_;
0693
0694 double mirror_r0[2] = {m_r0min, m_r0max};
0695 double mirror_r1[2] = {_CONICAL_MIRROR_INNER_RADIUS_, _CONICAL_MIRROR_OUTER_RADIUS_};
0696
0697 for (unsigned im = 0; im < 2; im++) {
0698
0699 double mirror_thickness = im ? _OUTER_MIRROR_THICKNESS_ : _INNER_MIRROR_THICKNESS_;
0700
0701 if (im) {
0702
0703 Cone mirror_outer_cone_shape(mlen / 2.0, mirror_r0[im], mirror_r0[im] + mirror_thickness,
0704 mirror_r1[im], mirror_r1[im] + mirror_thickness);
0705
0706 Volume outer_mirrorVol(detName + "_outer_mirror", mirror_outer_cone_shape, mirrorMat);
0707
0708 PlacedVolume mirror_outerPV = pfRICH_volume.placeVolume(outer_mirrorVol, Position(0, 0, 0));
0709
0710 DetElement mirror_outerDE(sdet, "_outer_mirror_de", 0);
0711 mirror_outerDE.setPlacement(mirror_outerPV);
0712
0713 } else {
0714
0715 Cone mirror_inner_cone_shape(mlen / 2., mirror_r0[im], mirror_r0[im] + mirror_thickness,
0716 mirror_r1[im], mirror_r1[im] + mirror_thickness);
0717
0718 SubtractionSolid mirror_inner_sub(mirror_inner_cone_shape, flange_final_shape);
0719
0720 Volume inner_mirrorVol(detName + "_inner_mirror", mirror_inner_sub, mirrorMat);
0721
0722 PlacedVolume mirror_innerPV = pfRICH_volume.placeVolume(inner_mirrorVol, Position(0, 0, 0));
0723
0724 DetElement mirror_innerDE(sdet, "_inner_mirror_de", 0);
0725 mirror_innerDE.setPlacement(mirror_innerPV);
0726 }
0727
0728 }
0729
0730
0731
0732 double acthick = _ACRYLIC_THICKNESS_;
0733
0734
0735 Tube ac_tube(m_r0min + 3, m_r0max - 1, acthick / 2, 0 * degree, 360 * degree);
0736 SubtractionSolid ac_shape(ac_tube, flange_final_shape);
0737
0738 Volume acVol(detName + "_ac", ac_shape, gasvolMat);
0739
0740 PlacedVolume ac_PV = pfRICH_volume.placeVolume(acVol, Position(0, 0, -21.3));
0741
0742 DetElement acDE(sdet, "ac_de", 0);
0743 acDE.setPlacement(ac_PV);
0744
0745 return sdet;
0746 }
0747
0748
0749 DECLARE_DETELEMENT(epic_PFRICH, createDetector)