File indexing completed on 2025-01-18 09:15:55
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include "DD4hep/DetFactoryHelper.h"
0016 #include "DD4hep/OpticalSurfaces.h"
0017 #include "DD4hep/Printout.h"
0018 #include "DDRec/DetectorData.h"
0019 #include "DDRec/Surface.h"
0020
0021 #include <XML/Helper.h>
0022
0023 using namespace dd4hep;
0024 using namespace dd4hep::rec;
0025
0026
0027 static Ref_t createDetector(Detector& desc, xml::Handle_t handle, SensitiveDetector sens) {
0028
0029 xml::DetElement detElem = handle;
0030 std::string detName = detElem.nameStr();
0031 int detID = detElem.id();
0032 xml::Component dims = detElem.dimensions();
0033 OpticalSurfaceManager surfMgr = desc.surfaceManager();
0034 DetElement det(detName, detID);
0035 sens.setType("tracker");
0036
0037
0038
0039 auto vesselZmin = dims.attr<double>(_Unicode(zmin));
0040 auto vesselLength = dims.attr<double>(_Unicode(length));
0041 auto vesselRmin0 = dims.attr<double>(_Unicode(rmin0));
0042 auto vesselRmin1 = dims.attr<double>(_Unicode(rmin1));
0043 auto vesselRmax0 = dims.attr<double>(_Unicode(rmax0));
0044 auto vesselRmax1 = dims.attr<double>(_Unicode(rmax1));
0045 auto vesselRmax2 = dims.attr<double>(_Unicode(rmax2));
0046 auto snoutLength = dims.attr<double>(_Unicode(snout_length));
0047 auto nSectors = dims.attr<int>(_Unicode(nsectors));
0048 auto wallThickness = dims.attr<double>(_Unicode(wall_thickness));
0049 auto windowThickness = dims.attr<double>(_Unicode(window_thickness));
0050 auto vesselMat = desc.material(detElem.attr<std::string>(_Unicode(material)));
0051 auto gasvolMat = desc.material(detElem.attr<std::string>(_Unicode(gas)));
0052 auto vesselVis = desc.visAttributes(detElem.attr<std::string>(_Unicode(vis_vessel)));
0053 auto gasvolVis = desc.visAttributes(detElem.attr<std::string>(_Unicode(vis_gas)));
0054
0055 auto radiatorElem = detElem.child(_Unicode(radiator));
0056 auto radiatorRmin = radiatorElem.attr<double>(_Unicode(rmin));
0057 auto radiatorRmax = radiatorElem.attr<double>(_Unicode(rmax));
0058 auto radiatorPitch = radiatorElem.attr<double>(_Unicode(pitch));
0059 auto radiatorFrontplane = radiatorElem.attr<double>(_Unicode(frontplane));
0060
0061 auto aerogelElem = radiatorElem.child(_Unicode(aerogel));
0062 auto aerogelMat = desc.material(aerogelElem.attr<std::string>(_Unicode(material)));
0063 auto aerogelVis = desc.visAttributes(aerogelElem.attr<std::string>(_Unicode(vis)));
0064 auto aerogelThickness = aerogelElem.attr<double>(_Unicode(thickness));
0065
0066 auto filterElem = radiatorElem.child(_Unicode(filter));
0067 auto filterMat = desc.material(filterElem.attr<std::string>(_Unicode(material)));
0068 auto filterVis = desc.visAttributes(filterElem.attr<std::string>(_Unicode(vis)));
0069 auto filterThickness = filterElem.attr<double>(_Unicode(thickness));
0070
0071 auto airgapElem = radiatorElem.child(_Unicode(airgap));
0072 auto airgapMat = desc.material(airgapElem.attr<std::string>(_Unicode(material)));
0073 auto airgapVis = desc.visAttributes(airgapElem.attr<std::string>(_Unicode(vis)));
0074 auto airgapThickness = airgapElem.attr<double>(_Unicode(thickness));
0075
0076 auto mirrorElem = detElem.child(_Unicode(mirror));
0077 auto mirrorMat = desc.material(mirrorElem.attr<std::string>(_Unicode(material)));
0078 auto mirrorVis = desc.visAttributes(mirrorElem.attr<std::string>(_Unicode(vis)));
0079 auto mirrorSurf = surfMgr.opticalSurface(mirrorElem.attr<std::string>(_Unicode(surface)));
0080 auto mirrorBackplane = mirrorElem.attr<double>(_Unicode(backplane));
0081 auto mirrorThickness = mirrorElem.attr<double>(_Unicode(thickness));
0082 auto mirrorRmin = mirrorElem.attr<double>(_Unicode(rmin));
0083 auto mirrorRmax = mirrorElem.attr<double>(_Unicode(rmax));
0084 auto mirrorPhiw = mirrorElem.attr<double>(_Unicode(phiw));
0085 auto focusTuneZ = mirrorElem.attr<double>(_Unicode(focus_tune_z));
0086 auto focusTuneX = mirrorElem.attr<double>(_Unicode(focus_tune_x));
0087
0088 auto sensorboxLength = desc.constant<double>("DRICH_sensorbox_length");
0089 auto sensorboxRmin = desc.constant<double>("DRICH_sensorbox_rmin");
0090 auto sensorboxRmax = desc.constant<double>("DRICH_sensorbox_rmax");
0091 auto sensorboxDphi = desc.constant<double>("DRICH_sensorbox_dphi");
0092
0093 auto pssElem = detElem.child(_Unicode(sensors)).child(_Unicode(pss));
0094 auto pssMat = desc.material(pssElem.attr<std::string>(_Unicode(material)));
0095 auto pssVis = desc.visAttributes(pssElem.attr<std::string>(_Unicode(vis)));
0096 auto pssSurf = surfMgr.opticalSurface(pssElem.attr<std::string>(_Unicode(surface)));
0097 auto pssSide = pssElem.attr<double>(_Unicode(side));
0098 auto pssThickness = pssElem.attr<double>(_Unicode(thickness));
0099
0100 auto resinElem = detElem.child(_Unicode(sensors)).child(_Unicode(resin));
0101 auto resinMat = desc.material(resinElem.attr<std::string>(_Unicode(material)));
0102 auto resinVis = desc.visAttributes(resinElem.attr<std::string>(_Unicode(vis)));
0103 auto resinSide = resinElem.attr<double>(_Unicode(side));
0104 auto resinThickness = resinElem.attr<double>(_Unicode(thickness));
0105
0106 auto pduElem = detElem.child(_Unicode(sensors)).child(_Unicode(pdu));
0107 auto pduNumSensors = desc.constant<int>("DRICH_pdu_num_sensors");
0108 auto pduSensorGap = desc.constant<double>("DRICH_pdu_sensor_gap");
0109 auto pduGap = desc.constant<double>("DRICH_pdu_gap");
0110
0111 auto sensorSphElem = detElem.child(_Unicode(sensors)).child(_Unicode(sphere));
0112 auto sensorSphRadius = sensorSphElem.attr<double>(_Unicode(radius));
0113 auto sensorSphCenterX = sensorSphElem.attr<double>(_Unicode(centerx));
0114 auto sensorSphCenterZ = sensorSphElem.attr<double>(_Unicode(centerz));
0115
0116 auto sensorSphPatchElem = detElem.child(_Unicode(sensors)).child(_Unicode(sphericalpatch));
0117 auto sensorSphPatchPhiw = sensorSphPatchElem.attr<double>(_Unicode(phiw));
0118 auto sensorSphPatchRmin = sensorSphPatchElem.attr<double>(_Unicode(rmin));
0119 auto sensorSphPatchRmax = sensorSphPatchElem.attr<double>(_Unicode(rmax));
0120 auto sensorSphPatchZmin = sensorSphPatchElem.attr<double>(_Unicode(zmin));
0121
0122 auto readoutName = detElem.attr<std::string>(_Unicode(readout));
0123
0124 auto debugOpticsMode = desc.constant<int>("DRICH_debug_optics");
0125 bool debugSector = desc.constant<int>("DRICH_debug_sector") == 1;
0126 bool debugMirror = desc.constant<int>("DRICH_debug_mirror") == 1;
0127 bool debugSensors = desc.constant<int>("DRICH_debug_sensors") == 1;
0128
0129
0130 bool debugOptics = debugOpticsMode > 0;
0131 if (debugOptics) {
0132 printout(WARNING, "DRICH_geo", "DEBUGGING DRICH OPTICS");
0133 switch (debugOpticsMode) {
0134 case 1:
0135 vesselMat = aerogelMat = filterMat = pssMat = gasvolMat = desc.material("VacuumOptical");
0136 break;
0137 case 2:
0138 vesselMat = aerogelMat = filterMat = pssMat = desc.material("VacuumOptical");
0139 break;
0140 case 3:
0141 vesselMat = aerogelMat = filterMat = gasvolMat = desc.material("VacuumOptical");
0142 break;
0143 default:
0144 printout(FATAL, "DRICH_geo", "UNKNOWN debugOpticsMode");
0145 return det;
0146 }
0147 }
0148
0149
0150 if (debugOptics || debugMirror || debugSensors)
0151 debugSector = true;
0152 if (debugSector)
0153 gasvolVis = vesselVis = desc.invisible();
0154
0155
0156
0157
0158
0159 std::vector<std::string> sensorIDfields = {"pdu", "sipm", "sector"};
0160 const auto& readoutCoder = *desc.readout(readoutName).idSpec().decoder();
0161
0162 uint64_t cellMask = 0;
0163 for (const auto& idField : sensorIDfields)
0164 cellMask |= readoutCoder[idField].mask();
0165 desc.add(Constant("DRICH_cell_mask", std::to_string(cellMask)));
0166
0167 auto encodeSensorID = [&readoutCoder](auto ids) {
0168 uint64_t enc = 0;
0169 for (const auto& [idField, idValue] : ids)
0170 enc |= uint64_t(idValue) << readoutCoder[idField].offset();
0171 return enc;
0172 };
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184 double tankLength = vesselLength - snoutLength;
0185 double vesselZmax = vesselZmin + vesselLength;
0186
0187
0188 double boreDelta = vesselRmin1 - vesselRmin0;
0189 double snoutDelta = vesselRmax1 - vesselRmax0;
0190 Cone vesselSnout(snoutLength / 2.0, vesselRmin0, vesselRmax0,
0191 vesselRmin0 + boreDelta * snoutLength / vesselLength, vesselRmax1);
0192 Cone gasvolSnout(
0193
0194
0195
0196
0197
0198 snoutLength / 2.0, vesselRmin0 + wallThickness, vesselRmax0 - wallThickness,
0199 vesselRmin0 + boreDelta * (snoutLength - windowThickness) / vesselLength + wallThickness,
0200 vesselRmax1 - wallThickness + windowThickness * (vesselRmax1 - vesselRmax0) / snoutLength);
0201
0202
0203
0204
0205 Polycone vesselTank(
0206 0, 2 * M_PI,
0207
0208 {vesselSnout.rMin2(),
0209 std::lerp(vesselSnout.rMin2(), vesselRmin1, (sensorboxLength - snoutLength) / tankLength),
0210 vesselRmin1},
0211 {vesselSnout.rMax2(), vesselRmax2, vesselRmax2},
0212
0213 {-tankLength / 2.0, -tankLength / 2.0 + sensorboxLength - snoutLength, tankLength / 2.0});
0214 Polycone gasvolTank(
0215 0, 2 * M_PI,
0216
0217 {gasvolSnout.rMin2(),
0218 std::lerp(gasvolSnout.rMin2(), vesselRmin1 + wallThickness,
0219 (sensorboxLength - snoutLength) / tankLength),
0220 vesselRmin1 + wallThickness},
0221 {gasvolSnout.rMax2(), vesselRmax2 - wallThickness, vesselRmax2 - wallThickness},
0222
0223 {-tankLength / 2.0 + windowThickness,
0224 -tankLength / 2.0 + windowThickness + sensorboxLength - snoutLength,
0225 tankLength / 2.0 - windowThickness});
0226
0227
0228 double dphi = atan2(wallThickness, sensorboxRmax);
0229 Tube vesselSensorboxTube(sensorboxRmin, sensorboxRmax, sensorboxLength / 2., -sensorboxDphi / 2.,
0230 sensorboxDphi / 2.);
0231 Tube gasvolSensorboxTube(sensorboxRmin + wallThickness, sensorboxRmax - wallThickness,
0232 sensorboxLength / 2., -sensorboxDphi / 2. + dphi,
0233 sensorboxDphi / 2. - dphi);
0234
0235
0236 UnionSolid vesselUnion(vesselTank, vesselSnout, Position(0., 0., -vesselLength / 2.));
0237 UnionSolid gasvolUnion(gasvolTank, gasvolSnout,
0238 Position(0., 0., -vesselLength / 2. + windowThickness));
0239
0240
0241 for (int isec = 0; isec < nSectors; isec++) {
0242 RotationZ sectorRotation((isec + 0.5) * 2 * M_PI / nSectors);
0243 vesselUnion = UnionSolid(
0244 vesselUnion, vesselSensorboxTube,
0245 Transform3D(sectorRotation, Position(0., 0., -(snoutLength + sensorboxLength - 0.6) / 2.)));
0246 gasvolUnion = UnionSolid(
0247 gasvolUnion, gasvolSensorboxTube,
0248 Transform3D(sectorRotation,
0249 Position(0., 0., -(snoutLength + sensorboxLength) / 2. + windowThickness)));
0250 }
0251
0252
0253 Box vesselBox(1001, 1001, 1001);
0254 Box gasvolBox(1000, 1000, 1000);
0255
0256
0257 Solid vesselSolid, gasvolSolid;
0258 switch (debugOpticsMode) {
0259 case 0:
0260 vesselSolid = vesselUnion;
0261 gasvolSolid = gasvolUnion;
0262 break;
0263 case 1:
0264 case 3:
0265 vesselSolid = vesselBox;
0266 gasvolSolid = gasvolBox;
0267 break;
0268 case 2:
0269 vesselSolid = vesselBox;
0270 gasvolSolid = gasvolUnion;
0271 break;
0272 }
0273
0274
0275 Volume vesselVol(detName, vesselSolid, vesselMat);
0276 Volume gasvolVol(detName + "_gas", gasvolSolid, gasvolMat);
0277 vesselVol.setVisAttributes(vesselVis);
0278 gasvolVol.setVisAttributes(gasvolVis);
0279
0280
0281
0282
0283
0284
0285
0286
0287 auto originFront = Position(0., 0., -tankLength / 2.0 - snoutLength);
0288
0289 auto vesselPos = Position(0, 0, vesselZmin) - originFront;
0290
0291
0292 PlacedVolume gasvolPV = vesselVol.placeVolume(gasvolVol, Position(0, 0, 0));
0293 DetElement gasvolDE(det, "gasvol_de", 0);
0294 gasvolDE.setPlacement(gasvolPV);
0295
0296
0297 Volume motherVol = desc.pickMotherVolume(det);
0298 PlacedVolume vesselPV = motherVol.placeVolume(vesselVol, vesselPos);
0299 vesselPV.addPhysVolID("system", detID);
0300 det.setPlacement(vesselPV);
0301
0302
0303
0304
0305 Cone aerogelSolid(aerogelThickness / 2, radiatorRmin, radiatorRmax,
0306 radiatorRmin + boreDelta * aerogelThickness / vesselLength,
0307 radiatorRmax + snoutDelta * aerogelThickness / snoutLength);
0308 Cone airgapSolid(airgapThickness / 2, radiatorRmin + boreDelta * aerogelThickness / vesselLength,
0309 radiatorRmax + snoutDelta * aerogelThickness / snoutLength,
0310 radiatorRmin + boreDelta * (aerogelThickness + airgapThickness) / vesselLength,
0311 radiatorRmax + snoutDelta * (aerogelThickness + airgapThickness) / snoutLength);
0312 Cone filterSolid(
0313 filterThickness / 2,
0314 radiatorRmin + boreDelta * (aerogelThickness + airgapThickness) / vesselLength,
0315 radiatorRmax + snoutDelta * (aerogelThickness + airgapThickness) / snoutLength,
0316 radiatorRmin +
0317 boreDelta * (aerogelThickness + airgapThickness + filterThickness) / vesselLength,
0318 radiatorRmax +
0319 snoutDelta * (aerogelThickness + airgapThickness + filterThickness) / snoutLength);
0320
0321 Volume aerogelVol(detName + "_aerogel", aerogelSolid, aerogelMat);
0322 Volume airgapVol(detName + "_airgap", airgapSolid, airgapMat);
0323 Volume filterVol(detName + "_filter", filterSolid, filterMat);
0324 aerogelVol.setVisAttributes(aerogelVis);
0325 airgapVol.setVisAttributes(airgapVis);
0326 filterVol.setVisAttributes(filterVis);
0327
0328
0329
0330
0331 auto radiatorPos = Position(0., 0., radiatorFrontplane + 0.5 * aerogelThickness) + originFront;
0332 auto aerogelPlacement = Translation3D(radiatorPos) *
0333 RotationY(radiatorPitch);
0334 auto aerogelPV = gasvolVol.placeVolume(aerogelVol, aerogelPlacement);
0335 DetElement aerogelDE(det, "aerogel_de", 0);
0336 aerogelDE.setPlacement(aerogelPV);
0337
0338
0339
0340
0341 if (!debugOptics) {
0342
0343 auto airgapPlacement =
0344 Translation3D(radiatorPos) *
0345 RotationY(radiatorPitch) *
0346 Translation3D(0., 0.,
0347 (aerogelThickness + airgapThickness) / 2.);
0348 auto airgapPV = gasvolVol.placeVolume(airgapVol, airgapPlacement);
0349 DetElement airgapDE(det, "airgap_de", 0);
0350 airgapDE.setPlacement(airgapPV);
0351
0352 auto filterPlacement =
0353 Translation3D(0., 0., airgapThickness) *
0354 Translation3D(radiatorPos) *
0355 RotationY(radiatorPitch) *
0356 Translation3D(0., 0.,
0357 (aerogelThickness + filterThickness) / 2.);
0358 auto filterPV = gasvolVol.placeVolume(filterVol, filterPlacement);
0359 DetElement filterDE(det, "filter_de", 0);
0360 filterDE.setPlacement(filterPV);
0361
0362
0363
0364
0365 double aerogelZpos = vesselPos.z() + aerogelPV.position().z();
0366 double airgapZpos = vesselPos.z() + airgapPV.position().z();
0367 double filterZpos = vesselPos.z() + filterPV.position().z();
0368 desc.add(Constant("DRICH_aerogel_zpos", std::to_string(aerogelZpos)));
0369 desc.add(Constant("DRICH_airgap_zpos", std::to_string(airgapZpos)));
0370 desc.add(Constant("DRICH_filter_zpos", std::to_string(filterZpos)));
0371 }
0372
0373
0374 desc.add(Constant("DRICH_aerogel_material", aerogelMat.ptr()->GetName(), "string"));
0375 desc.add(Constant("DRICH_airgap_material", airgapMat.ptr()->GetName(), "string"));
0376 desc.add(Constant("DRICH_filter_material", filterMat.ptr()->GetName(), "string"));
0377 desc.add(Constant("DRICH_gasvol_material", gasvolMat.ptr()->GetName(), "string"));
0378
0379
0380 for (int isec = 0; isec < nSectors; isec++) {
0381
0382
0383 if (debugSector && isec != 0)
0384 continue;
0385
0386
0387 RotationZ sectorRotation((isec + 0.5) * 2 * M_PI / nSectors);
0388 std::string secName = "sec" + std::to_string(isec);
0389
0390
0391
0392
0393
0394 double zS = sensorSphCenterZ + vesselZmin;
0395 double xS = sensorSphCenterX;
0396
0397 double b = vesselZmax - mirrorBackplane;
0398
0399 double zF = zS + focusTuneZ;
0400 double xF = xS + focusTuneX;
0401
0402
0403
0404
0405
0406
0407
0408
0409 double mirrorCenterZ = b * zF / (2 * b - zF);
0410 double mirrorCenterX = b * xF / (2 * b - zF);
0411 double mirrorRadius = b - mirrorCenterZ;
0412
0413
0414 mirrorCenterZ -= vesselZmin;
0415
0416
0417 double mirrorThetaRot = std::asin(mirrorCenterX / mirrorRadius);
0418 double mirrorTheta1 = mirrorThetaRot - std::asin((mirrorCenterX - mirrorRmin) / mirrorRadius);
0419 double mirrorTheta2 = mirrorThetaRot + std::asin((mirrorRmax - mirrorCenterX) / mirrorRadius);
0420
0421
0422 if (debugMirror) {
0423 mirrorTheta1 = 0;
0424 mirrorTheta2 = M_PI;
0425 }
0426
0427
0428
0429 Sphere mirrorSolid1(mirrorRadius, mirrorRadius + mirrorThickness, mirrorTheta1, mirrorTheta2,
0430 -40 * degree, 40 * degree);
0431
0432
0433 auto mirrorPos = Position(mirrorCenterX, 0., mirrorCenterZ) + originFront;
0434 auto mirrorPlacement(
0435 Translation3D(mirrorPos) *
0436 RotationY(-mirrorThetaRot)
0437 );
0438
0439
0440
0441 Tube pieSlice(0.01 * cm, vesselRmax2, tankLength / 2.0, -mirrorPhiw / 2.0, mirrorPhiw / 2.0);
0442 IntersectionSolid mirrorSolid2(pieSlice, mirrorSolid1, mirrorPlacement);
0443
0444
0445 Volume mirrorVol(detName + "_mirror_" + secName, mirrorSolid2, mirrorMat);
0446 mirrorVol.setVisAttributes(mirrorVis);
0447 auto mirrorSectorPlacement = Transform3D(sectorRotation);
0448 auto mirrorPV = gasvolVol.placeVolume(mirrorVol, mirrorSectorPlacement);
0449
0450
0451 DetElement mirrorDE(det, "mirror_de_" + secName, isec);
0452 mirrorDE.setPlacement(mirrorPV);
0453 SkinSurface mirrorSkin(desc, mirrorDE, "mirror_optical_surface_" + secName, mirrorSurf,
0454 mirrorVol);
0455 mirrorSkin.isValid();
0456
0457
0458
0459 auto mirrorFinalPlacement = mirrorSectorPlacement * mirrorPlacement;
0460 auto mirrorFinalCenter = vesselPos + mirrorFinalPlacement.Translation().Vect();
0461 desc.add(Constant("DRICH_mirror_center_x_" + secName, std::to_string(mirrorFinalCenter.x())));
0462 desc.add(Constant("DRICH_mirror_center_y_" + secName, std::to_string(mirrorFinalCenter.y())));
0463 desc.add(Constant("DRICH_mirror_center_z_" + secName, std::to_string(mirrorFinalCenter.z())));
0464 if (isec == 0)
0465 desc.add(Constant("DRICH_mirror_radius", std::to_string(mirrorRadius)));
0466
0467
0468
0469
0470 if (debugSensors) {
0471 pssSide = 2 * M_PI * sensorSphRadius / 64;
0472 }
0473
0474
0475 auto sensorSphPos = Position(sensorSphCenterX, 0., sensorSphCenterZ) + originFront;
0476 auto sensorSphFinalCenter = sectorRotation * Position(xS, 0.0, zS);
0477 desc.add(
0478 Constant("DRICH_sensor_sph_center_x_" + secName, std::to_string(sensorSphFinalCenter.x())));
0479 desc.add(
0480 Constant("DRICH_sensor_sph_center_y_" + secName, std::to_string(sensorSphFinalCenter.y())));
0481 desc.add(
0482 Constant("DRICH_sensor_sph_center_z_" + secName, std::to_string(sensorSphFinalCenter.z())));
0483 if (isec == 0)
0484 desc.add(Constant("DRICH_sensor_sph_radius", std::to_string(sensorSphRadius)));
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506 int ipdu = 0;
0507
0508
0509 double pduPitch = pduNumSensors * resinSide + (pduNumSensors + 1) * pduSensorGap + pduGap;
0510
0511
0512 double nTheta = M_PI * sensorSphRadius / pduPitch;
0513 for (int t = 0; t < (int)(nTheta + 0.5); t++) {
0514 double thetaGen = t / ((double)nTheta) * M_PI;
0515
0516
0517 double nPhi = 2 * M_PI * sensorSphRadius * std::sin(thetaGen) / pduPitch;
0518 for (int p = 0; p < (int)(nPhi + 0.5); p++) {
0519 double phiGen = p / ((double)nPhi) * 2 * M_PI - M_PI;
0520
0521
0522
0523 double xGen = sensorSphRadius * std::sin(thetaGen) * std::cos(phiGen);
0524 double yGen = sensorSphRadius * std::sin(thetaGen) * std::sin(phiGen);
0525 double zGen = sensorSphRadius * std::cos(thetaGen);
0526
0527 double x = zGen;
0528 double y = xGen;
0529 double z = yGen;
0530
0531
0532
0533
0534
0535 double zCheck = z + sensorSphCenterZ;
0536 double xCheck = x + sensorSphCenterX;
0537 double yCheck = y;
0538 double rCheck = std::hypot(xCheck, yCheck);
0539 double phiCheck = std::atan2(yCheck, xCheck);
0540
0541
0542 bool patchCut = std::fabs(phiCheck) < sensorSphPatchPhiw && zCheck > sensorSphPatchZmin &&
0543 rCheck > sensorSphPatchRmin && rCheck < sensorSphPatchRmax;
0544 if (debugSensors)
0545 patchCut = std::fabs(phiCheck) < sensorSphPatchPhiw;
0546 if (patchCut) {
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564 Box pssSolid(pssSide / 2., pssSide / 2., pssThickness / 2.);
0565 Box resinSolid(resinSide / 2., resinSide / 2., resinThickness / 2.);
0566
0567
0568 SubtractionSolid resinSolidEmbedded(
0569 resinSolid, pssSolid,
0570 Transform3D(Translation3D(0., 0., (resinThickness - pssThickness) / 2.)));
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585 Volume pssVol(detName + "_pss_" + secName, pssSolid, pssMat);
0586 Volume resinVol(detName + "_resin_" + secName, resinSolidEmbedded, resinMat);
0587 pssVol.setVisAttributes(pssVis);
0588 resinVol.setVisAttributes(resinVis);
0589
0590
0591 if (!debugOptics || debugOpticsMode == 3)
0592 pssVol.setSensitiveDetector(sens);
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602 auto pduAssemblyPlacement =
0603 sectorRotation *
0604 Translation3D(sensorSphPos) *
0605 RotationX(phiGen) *
0606 RotationZ(thetaGen) *
0607 Translation3D(sensorSphRadius, 0., 0.) *
0608 RotationY(M_PI / 2) *
0609 RotationZ(-M_PI / 2);
0610
0611
0612
0613 Assembly pduAssembly(detName + "_pdu_" + secName);
0614 double pduSensorPitch = resinSide + pduSensorGap;
0615 double pduSensorOffsetMax = pduSensorPitch * (pduNumSensors - 1) / 2.0;
0616 int isipm = 0;
0617 for (int sensorIx = 0; sensorIx < pduNumSensors; sensorIx++) {
0618 for (int sensorIy = 0; sensorIy < pduNumSensors; sensorIy++) {
0619
0620 Assembly sensorAssembly(detName + "_sensor_" + secName);
0621
0622
0623
0624 auto pssPlacement = Transform3D(Translation3D(
0625 0., 0.,
0626 -pssThickness / 2.0));
0627 auto resinPlacement = Transform3D(Translation3D(0., 0., -resinThickness / 2.0));
0628
0629 auto pduSensorOffsetX = sensorIx * pduSensorPitch - pduSensorOffsetMax;
0630 auto pduSensorOffsetY = sensorIy * pduSensorPitch - pduSensorOffsetMax;
0631 auto sensorAssemblyPlacement =
0632 Transform3D(Translation3D(pduSensorOffsetX, pduSensorOffsetY, 0.0));
0633
0634
0635 auto pssPV = sensorAssembly.placeVolume(pssVol, pssPlacement);
0636 sensorAssembly.placeVolume(resinVol, resinPlacement);
0637 pduAssembly.placeVolume(sensorAssembly, sensorAssemblyPlacement);
0638
0639
0640 pssPV.addPhysVolID("sector", isec)
0641 .addPhysVolID("pdu", ipdu)
0642 .addPhysVolID("sipm", isipm);
0643
0644
0645 auto sensorID = encodeSensorID(pssPV.volIDs());
0646 std::string sensorIDname =
0647 secName + "_pdu" + std::to_string(ipdu) + "_sipm" + std::to_string(isipm);
0648 DetElement pssDE(det, "sensor_de_" + sensorIDname, sensorID);
0649 pssDE.setPlacement(pssPV);
0650
0651
0652 if (!debugOptics || debugOpticsMode == 3) {
0653 SkinSurface pssSkin(desc, pssDE, "sensor_optical_surface_" + sensorIDname, pssSurf,
0654 pssVol);
0655 pssSkin.isValid();
0656 }
0657
0658
0659
0660 auto pduOrigin = ROOT::Math::XYZPoint(0, 0, 0);
0661 auto sensorPos = Translation3D(vesselPos) *
0662 pduAssemblyPlacement *
0663 sensorAssemblyPlacement *
0664 pduOrigin;
0665 auto pduPos = Translation3D(vesselPos) *
0666 pduAssemblyPlacement *
0667 pduOrigin;
0668
0669
0670
0671 auto normVector = [pduAssemblyPlacement](Direction n) {
0672 return pduAssemblyPlacement * n;
0673 };
0674 auto sensorNormX = normVector(Direction{
0675 1.,
0676 0.,
0677 0.,
0678 });
0679 auto sensorNormY = normVector(Direction{
0680 0.,
0681 1.,
0682 0.,
0683 });
0684
0685
0686
0687
0688
0689
0690
0691
0692 auto distActual = std::sqrt((sensorPos - sensorSphFinalCenter).Mag2());
0693 auto distExpected = std::hypot(pduSensorOffsetX, pduSensorOffsetY, sensorSphRadius);
0694 auto testOnSphere = distActual - distExpected;
0695 if (std::abs(testOnSphere) > 1e-6) {
0696 printout(ERROR, "DRICH_geo", "sensor %s failed on-sphere test; testOnSphere=%f",
0697 sensorIDname.c_str(), testOnSphere);
0698 throw std::runtime_error("dRICH sensor position test failed");
0699 }
0700
0701 Direction radialDir =
0702 Direction(pduPos) - sensorSphFinalCenter;
0703 auto sensorNormZ = sensorNormX.Cross(sensorNormY);
0704 auto testOrtho =
0705 sensorNormX.Dot(sensorNormY);
0706 auto testRadial =
0707 radialDir.Cross(sensorNormZ)
0708 .Mag2();
0709 auto testDirection = radialDir.Dot(
0710 sensorNormZ);
0711 if (std::abs(testOrtho) > 1e-6 || std::abs(testRadial) > 1e-6 || testDirection <= 0) {
0712 printout(ERROR, "DRICH_geo", "sensor %s failed orientation test",
0713 sensorIDname.c_str());
0714 printout(ERROR, "DRICH_geo", " testOrtho = %f; should be zero", testOrtho);
0715 printout(ERROR, "DRICH_geo", " testRadial = %f; should be zero", testRadial);
0716 printout(ERROR, "DRICH_geo", " testDirection = %f; should be positive",
0717 testDirection);
0718 throw std::runtime_error("dRICH sensor orientation test failed");
0719 }
0720
0721
0722 auto pssVarMap = pssDE.extension<VariantParameters>(false);
0723 if (pssVarMap == nullptr) {
0724 pssVarMap = new VariantParameters();
0725 pssDE.addExtension<VariantParameters>(pssVarMap);
0726 }
0727 auto addVecToMap = [pssVarMap](std::string key, auto vec) {
0728 pssVarMap->set<double>(key + "_x", vec.x());
0729 pssVarMap->set<double>(key + "_y", vec.y());
0730 pssVarMap->set<double>(key + "_z", vec.z());
0731 };
0732 addVecToMap("pos", sensorPos);
0733 addVecToMap("normX", sensorNormX);
0734 addVecToMap("normY", sensorNormY);
0735 printout(DEBUG, "DRICH_geo", "sensor %s:", sensorIDname.c_str());
0736 for (auto kv : pssVarMap->variantParameters)
0737 printout(DEBUG, "DRICH_geo", " %s: %f", kv.first.c_str(),
0738 pssVarMap->get<double>(kv.first));
0739
0740
0741 isipm++;
0742 }
0743 }
0744
0745
0746 Transform3D frontServiceTransformation =
0747 Transform3D(Translation3D(0., 0., -resinThickness));
0748 for (xml::Collection_t serviceElem(pduElem.child(_Unicode(frontservices)),
0749 _Unicode(service));
0750 serviceElem; ++serviceElem) {
0751 auto serviceName = serviceElem.attr<std::string>(_Unicode(name));
0752 auto serviceSide = serviceElem.attr<double>(_Unicode(side));
0753 auto serviceThickness = serviceElem.attr<double>(_Unicode(thickness));
0754 auto serviceMat = desc.material(serviceElem.attr<std::string>(_Unicode(material)));
0755 auto serviceVis = desc.visAttributes(serviceElem.attr<std::string>(_Unicode(vis)));
0756 Box serviceSolid(serviceSide / 2.0, serviceSide / 2.0, serviceThickness / 2.0);
0757 Volume serviceVol(detName + "_" + serviceName + "_" + secName, serviceSolid,
0758 serviceMat);
0759 serviceVol.setVisAttributes(serviceVis);
0760 frontServiceTransformation =
0761 Transform3D(Translation3D(0., 0., -serviceThickness / 2.0)) *
0762 frontServiceTransformation;
0763 pduAssembly.placeVolume(serviceVol, frontServiceTransformation);
0764 frontServiceTransformation =
0765 Transform3D(Translation3D(0., 0., -serviceThickness / 2.0)) *
0766 frontServiceTransformation;
0767 }
0768
0769
0770 auto boardsElem = pduElem.child(_Unicode(boards));
0771 auto boardsMat = desc.material(boardsElem.attr<std::string>(_Unicode(material)));
0772 auto boardsVis = desc.visAttributes(boardsElem.attr<std::string>(_Unicode(vis)));
0773 Transform3D backServiceTransformation;
0774 for (xml::Collection_t boardElem(boardsElem, _Unicode(board)); boardElem; ++boardElem) {
0775 auto boardName = boardElem.attr<std::string>(_Unicode(name));
0776 auto boardWidth = boardElem.attr<double>(_Unicode(width));
0777 auto boardLength = boardElem.attr<double>(_Unicode(length));
0778 auto boardThickness = boardElem.attr<double>(_Unicode(thickness));
0779 auto boardOffset = boardElem.attr<double>(_Unicode(offset));
0780 Box boardSolid(boardWidth / 2.0, boardThickness / 2.0, boardLength / 2.0);
0781 Volume boardVol(detName + "_" + boardName + "+" + secName, boardSolid, boardsMat);
0782 boardVol.setVisAttributes(boardsVis);
0783 auto boardTransformation =
0784 Translation3D(0., boardOffset, -boardLength / 2.0) * frontServiceTransformation;
0785 pduAssembly.placeVolume(boardVol, boardTransformation);
0786 if (boardName == "RDO")
0787 backServiceTransformation =
0788 Translation3D(0., 0., -boardLength) * frontServiceTransformation;
0789 }
0790
0791
0792 for (xml::Collection_t serviceElem(pduElem.child(_Unicode(backservices)),
0793 _Unicode(service));
0794 serviceElem; ++serviceElem) {
0795 auto serviceName = serviceElem.attr<std::string>(_Unicode(name));
0796 auto serviceSide = serviceElem.attr<double>(_Unicode(side));
0797 auto serviceThickness = serviceElem.attr<double>(_Unicode(thickness));
0798 auto serviceMat = desc.material(serviceElem.attr<std::string>(_Unicode(material)));
0799 auto serviceVis = desc.visAttributes(serviceElem.attr<std::string>(_Unicode(vis)));
0800 Box serviceSolid(serviceSide / 2.0, serviceSide / 2.0, serviceThickness / 2.0);
0801 Volume serviceVol(detName + "_" + serviceName + "_" + secName, serviceSolid,
0802 serviceMat);
0803 serviceVol.setVisAttributes(serviceVis);
0804 backServiceTransformation =
0805 Transform3D(Translation3D(0., 0., -serviceThickness / 2.0)) *
0806 backServiceTransformation;
0807 pduAssembly.placeVolume(serviceVol, backServiceTransformation);
0808 backServiceTransformation =
0809 Transform3D(Translation3D(0., 0., -serviceThickness / 2.0)) *
0810 backServiceTransformation;
0811 }
0812
0813
0814 gasvolVol.placeVolume(pduAssembly, pduAssemblyPlacement);
0815
0816
0817 ipdu++;
0818
0819 }
0820 }
0821 }
0822
0823
0824
0825
0826 if (isec == 0)
0827 desc.add(Constant("DRICH_num_pdus", std::to_string(ipdu)));
0828 else if (ipdu != desc.constant<int>("DRICH_num_pdus"))
0829 printout(WARNING, "DRICH_geo", "number of PDUs is not the same for each sector");
0830
0831 }
0832
0833 return det;
0834 }
0835
0836
0837 DECLARE_DETELEMENT(epic_DRICH, createDetector)