10#include <klm/bklm/geometry/GeoBKLMCreator.h>
13#include <klm/dataobjects/bklm/BKLMElementNumbers.h>
14#include <klm/dataobjects/KLMElementNumbers.h>
15#include <klm/dbobjects/bklm/BKLMGeometryPar.h>
16#include <klm/simulation/SensitiveDetector.h>
19#include <geometry/Materials.h>
23#include <G4LogicalVolume.hh>
24#include <G4Polyhedra.hh>
25#include <G4PVPlacement.hh>
28#include <G4SubtractionSolid.hh>
29#include <G4Transform3D.hh>
31#include <G4UnionSolid.hh>
32#include <G4VisAttributes.hh>
34using namespace Belle2::bklm;
87 for (G4String* name :
m_Names)
delete name;
104 G4Tubs* envelopeSolid =
105 new G4Tubs(
"BKLM.EnvelopeSolid",
106 m_GeoPar->getSolenoidOuterRadius() * CLHEP::cm,
112 G4LogicalVolume* envelopeLogical =
113 new G4LogicalVolume(envelopeSolid,
115 "BKLM.EnvelopeLogical"
120 G4Region* aRegion =
new G4Region(
"BKLMEnvelope");
121 envelopeLogical->SetRegion(aRegion);
122 aRegion->AddRootLogicalVolume(envelopeLogical);
124 new G4PVPlacement(G4TranslateZ3D(
m_GeoPar->getOffsetZ() * CLHEP::cm) * G4RotateZ3D(
m_GeoPar->getRotation() * CLHEP::rad),
126 "BKLM.EnvelopePhysical",
138 new G4Tubs(
"BKLM.EndSolid",
139 m_GeoPar->getSolenoidOuterRadius() * CLHEP::cm,
145 G4LogicalVolume* frontLogical =
146 new G4LogicalVolume(endSolid,
160 G4LogicalVolume* backLogical =
161 new G4LogicalVolume(endSolid,
167 new G4PVPlacement(G4TranslateZ3D(-
m_SectorDz) * G4RotateY3D(M_PI),
182 new G4Tubs(
"BKLM.SectorSolid",
183 m_GeoPar->getSolenoidOuterRadius() * CLHEP::cm,
191 for (
int s = 0; s <
m_GeoPar->getNSector(); ++s) {
194 bool hasInnerSupport = (sector <=
m_GeoPar->getNSector() / 2 + 1);
220 const CLHEP::Hep3Vector gapHalfSize =
m_GeoPar->getGapHalfSize(0,
false) * CLHEP::cm;
221 const double dyBrace = (hasChimney ?
m_GeoPar->getBraceWidthChimney() :
m_GeoPar->getBraceWidth()) * CLHEP::cm;
222 const double dy = 0.25 * (
m_GeoPar->getCablesWidth() * CLHEP::cm - dyBrace);
223 const double dz =
m_SectorDz - gapHalfSize.z();
224 const double ri =
m_GeoPar->getLayerInnerRadius(1) * CLHEP::cm + 2.0 * gapHalfSize.x();
225 const double ro =
m_GeoPar->getOuterRadius() * CLHEP::cm;
227 const double z[2] = { -dz, dz};
228 const double rInner[2] = {ri, ri};
229 const double rOuter[2] = {ro, ro};
231 new G4Polyhedra(
"BKLM.CapSolid",
238 int newLvol = (hasChimney ? 1 : 0);
239 G4String name = (hasChimney ?
"BKLM.ChimneyCapLogical" :
"BKLM.CapLogical");
247 name = (hasChimney ?
"BKLM.ChimneyCablesSolid" :
"BKLM.CablesSolid");
249 new G4Box(name, 0.5 * (ro - ri), dy, dz);
250 G4LogicalVolume* cablesLogical =
251 new G4LogicalVolume(cablesSolid,
256 new G4PVPlacement(G4Translate3D(0.5 * (ri + ro), -(0.5 * dyBrace + dy), 0.0),
264 new G4PVPlacement(G4Translate3D(0.5 * (ri + ro), +(0.5 * dyBrace + dy), 0.0),
273 new G4PVPlacement(G4TranslateZ3D(
m_SectorDz - dz),
288 const double r =
m_GeoPar->getLayerInnerRadius(1) * CLHEP::cm;
290 const double rInner[2] = {0.0, 0.0};
291 const double rOuter[2] = {r, r};
292 G4Polyhedra* innerIronPolygon =
293 new G4Polyhedra(
"BKLM.InnerIronPolygon",
300 new G4SubtractionSolid(
"BKLM.InnerIronSolid",
305 int newLvol = (hasInnerSupport ? 2 : 0) + (hasChimney ? 1 : 0);
310 (hasChimney ?
"BKLM.InnerIronChimneyLogical" :
"BKLM.InnerIronLogical")
315 new G4PVPlacement(G4TranslateZ3D(0.0),
333 const double rInner[2] = {0.0, 0.0};
334 const double rOuter[2] = {r, r};
335 G4Polyhedra* innerAirPolygon =
336 new G4Polyhedra(
"BKLM.InnerAirPolygon",
343 new G4SubtractionSolid(
"BKLM.InnerAirSolid",
349 int newLvol = (hasInnerSupport ? 2 : 0) + (hasChimney ? 1 : 0);
354 (hasChimney ?
"BKLM.InnerAirChimneyLogical" :
"BKLM.InnerAirLogical")
357 if (hasInnerSupport) {
375 int newLvol = (hasChimney ? 1 : 0);
376 const CLHEP::Hep3Vector size =
m_GeoPar->getSupportPlateHalfSize(hasChimney) * CLHEP::cm;
379 new G4Box((hasChimney ?
"BKLM.ChimneySupportSolid" :
"BKLM.SupportSolid"),
385 new G4LogicalVolume(supportBox,
393 new G4PVPlacement(G4Translate3D(dx, 0.0, dz),
407 const CLHEP::Hep3Vector size =
m_GeoPar->getSupportPlateHalfSize(hasChimney) * CLHEP::cm;
408 const double dz = 0.5 *
m_GeoPar->getBracketLength() * CLHEP::cm;
409 const double r =
m_GeoPar->getLayerInnerRadius(1) * CLHEP::cm -
m_RibShift - 2.0 * size.x();
410 const double bracketShift =
m_GeoPar->getBracketRibThickness() * CLHEP::cm / sin(0.5 *
m_SectorDphi);
411 const double z[2] = { -dz, +dz};
412 const double rInner[2] = {0.0, 0.0};
413 const double rOuter[2] = {r, r};
415 const double z1[2] = { -(dz + 0.5 * CLHEP::cm), dz + 0.5 * CLHEP::cm};
416 const double rOuter1[2] = {r1, r1};
417 const double z2[2] = { -(dz + 1.0 * CLHEP::cm), dz + 1.0 * CLHEP::cm};
418 const double dzBracket =
m_GeoPar->getBracketThickness() * CLHEP::cm;
419 const double drBracket = dzBracket + bracketShift;
420 const double rOuter2[2] = {r - drBracket, r - drBracket};
421 const double z3[2] = { -dzBracket, dzBracket};
422 const double cutoutDphi =
m_GeoPar->getBracketCutoutDphi() * CLHEP::rad;
423 G4Polyhedra* bracketPolygon =
424 new G4Polyhedra(
"BKLM.BracketPolygon",
430 G4Polyhedra* bracketCutout1 =
431 new G4Polyhedra(
"BKLM.BracketCutout1",
435 2, z1, rInner, rOuter1
437 G4Polyhedra* bracketCutout2 =
438 new G4Polyhedra(
"BKLM.BracketCutout2",
442 2, z2, rInner, rOuter2
444 G4Polyhedra* bracketCutout3 =
445 new G4Polyhedra(
"BKLM.BracketCutout3",
449 2, z3, rInner, rOuter2
451 G4Box* bracketCutout4 =
452 new G4Box(
"BKLM.BracketCutout4",
453 rOuter[1] + 1.0 * CLHEP::cm,
455 z[1] + 1.5 * CLHEP::cm
458 new G4SubtractionSolid(
"BKLM.BracketPolygon1",
463 new G4SubtractionSolid(
"BKLM.BracketPolygon2",
468 new G4SubtractionSolid(
"BKLM.BracketPolygon3",
471 G4TranslateX3D(bracketShift)
473 G4VSolid* bracketSolid =
474 new G4SubtractionSolid(
"BKLM.BracketSolid",
479 new G4LogicalVolume(bracketSolid,
481 "BKLM.BracketLogical"
488 for (
int bracket = 0; bracket < (hasChimney ? 2 : 3); ++bracket) {
489 sprintf(name,
"BKLM.Bracket%d%sPhysical", bracket, (hasChimney ?
"Chimney" :
""));
490 new G4PVPlacement(G4TranslateZ3D(
m_GeoPar->getBracketZPosition(bracket, hasChimney) * CLHEP::cm),
504 const double dz = 0.5 *
m_GeoPar->getGapLength() * CLHEP::cm;
505 const double z[2] = { -dz, +dz };
507 for (
int layer = 1; layer <=
m_GeoPar->getNLayer(); ++layer) {
510 const double ri =
m_GeoPar->getLayerInnerRadius(layer) * CLHEP::cm;
511 const double ro =
m_GeoPar->getLayerOuterRadius(layer) * CLHEP::cm;
512 const double rInner[2] = {ri, ri};
513 const double rOuter[2] = {ro, ro};
514 sprintf(name,
"BKLM.Layer%02dIronSolid", layer);
516 new G4Polyhedra(name,
524 bool isFlipped =
module->isFlipped();
526 (hasChimney ? 1 : 0)) + (layer - 1);
528 int s2 =
m_GeoPar->getNSector() / 2;
530 }
else if (s1 > s2) {
536 sprintf(name,
"BKLM.Layer%02d%s%sIronLogical", layer, (isFlipped ?
"Flipped" :
""), (hasChimney ?
"Chimney" :
""));
548 new G4PVPlacement(G4TranslateZ3D(dz -
m_SectorDz),
562 CLHEP::Hep3Vector gapHalfSize =
m_GeoPar->getGapHalfSize(layer,
true) * CLHEP::cm;
563 CLHEP::Hep3Vector chimneyHalfSize =
m_GeoPar->getChimneyHalfSize(layer) * CLHEP::cm;
564 CLHEP::Hep3Vector chimneyPosition =
m_GeoPar->getChimneyPosition(layer) * CLHEP::cm;
565 gapHalfSize.setY(0.5 * (gapHalfSize.y() - chimneyHalfSize.y()));
566 gapHalfSize.setZ(chimneyHalfSize.z() + 0.5 *
m_GeoPar->getChimneyCoverThickness() * CLHEP::cm);
567 double dx =
m_GeoPar->getGapMiddleRadius(layer) * CLHEP::cm;
568 double dy = gapHalfSize.y() + chimneyHalfSize.y();
569 double dz = 0.5 *
m_GeoPar->getGapLength() * CLHEP::cm - gapHalfSize.z();
572 sprintf(name,
"BKLM.Layer%02dGapChimneyBox", layer);
575 gapHalfSize.x(), gapHalfSize.y(), gapHalfSize.z()
577 sprintf(name,
"BKLM.Layer%02dGapChimneyLogical", layer);
578 G4LogicalVolume* gapLogical =
579 new G4LogicalVolume(gapBox,
584 sprintf(name,
"BKLM.Layer%02dLeftGapChimneyPhysical", layer);
585 new G4PVPlacement(G4Translate3D(dx, -dy, dz),
593 sprintf(name,
"BKLM.Layer%02dRightGapChimneyPhysical", layer);
594 new G4PVPlacement(G4Translate3D(dx, +dy, dz),
603 sprintf(name,
"BKLM.Layer%02dChimneyBox", layer);
606 chimneyHalfSize.x(), chimneyHalfSize.y(), chimneyHalfSize.z()
608 sprintf(name,
"BKLM.Layer%02dChimneyLogical", layer);
609 G4LogicalVolume* chimneyLogical =
610 new G4LogicalVolume(chimneyBox,
616 G4Tubs* housingTube =
617 new G4Tubs(
"BKLM.ChimneyHousingTube",
618 m_GeoPar->getChimneyHousingInnerRadius() * CLHEP::cm,
619 m_GeoPar->getChimneyHousingOuterRadius() * CLHEP::cm,
624 G4LogicalVolume* housingLogical =
625 new G4LogicalVolume(housingTube,
627 "BKLM.ChimneyHousingLogical"
632 new G4PVPlacement(G4RotateY3D(M_PI_2),
634 "BKLM.ChimneyHousingPhysical",
641 new G4Tubs(
"BKLM.ChimneyShieldTube",
642 m_GeoPar->getChimneyShieldInnerRadius() * CLHEP::cm,
643 m_GeoPar->getChimneyShieldOuterRadius() * CLHEP::cm,
648 G4LogicalVolume* shieldLogical =
649 new G4LogicalVolume(shieldTube,
651 "BKLM.ChimneyShieldLogical"
654 new G4PVPlacement(G4RotateY3D(M_PI_2),
656 "BKLM.ChimneyShieldPhysical",
663 new G4Tubs(
"BKLM.ChimneyPipeTube",
664 m_GeoPar->getChimneyPipeInnerRadius() * CLHEP::cm,
665 m_GeoPar->getChimneyPipeOuterRadius() * CLHEP::cm,
670 G4LogicalVolume* pipeLogical =
671 new G4LogicalVolume(pipeTube,
673 "BKLM.ChimneyPipeLogical"
678 new G4PVPlacement(G4RotateY3D(M_PI_2),
680 "BKLM.ChimneyPipePhysical",
686 sprintf(name,
"BKLM.Layer%02dChimneyPhysical", layer);
687 new G4PVPlacement(G4Translate3D(chimneyPosition),
698 bool isFlipped,
int newLvol)
700 const CLHEP::Hep3Vector gapHalfSize =
m_GeoPar->getGapHalfSize(layer, hasChimney) * CLHEP::cm;
701 const CLHEP::Hep3Vector moduleHalfSize =
m_GeoPar->getModuleHalfSize(layer, hasChimney) * CLHEP::cm;
707 sprintf(name,
"BKLM.Layer%02d%sModuleSolid", layer, (hasChimney ?
"Chimney" :
""));
710 moduleHalfSize.x(), moduleHalfSize.y(), moduleHalfSize.z()
713 new G4LogicalVolume(moduleBox,
718 sprintf(name,
"BKLM.Layer%02d%sModuleInteriorSolid1", layer, (hasChimney ?
"Chimney" :
""));
719 const CLHEP::Hep3Vector interiorHalfSize1 =
m_GeoPar->getModuleInteriorHalfSize1(layer, hasChimney) * CLHEP::cm;
720 G4Box* interiorBox1 =
722 interiorHalfSize1.x(), interiorHalfSize1.y(), interiorHalfSize1.z()
724 sprintf(name,
"BKLM.Layer%02d%sModuleInteriorSolid2", layer, (hasChimney ?
"Chimney" :
""));
725 const CLHEP::Hep3Vector interiorHalfSize2 =
m_GeoPar->getModuleInteriorHalfSize2(layer, hasChimney) * CLHEP::cm;
726 G4Box* interiorBox2 =
728 interiorHalfSize2.x(), interiorHalfSize2.y(), interiorHalfSize2.z()
730 sprintf(name,
"BKLM.Layer%02d%sModuleInteriorSolid", layer, (hasChimney ?
"Chimney" :
""));
731 G4UnionSolid* interiorUnion =
732 new G4UnionSolid(name, interiorBox1, interiorBox2);
733 G4LogicalVolume* interiorLogical =
734 new G4LogicalVolume(interiorUnion,
744 new G4PVPlacement(G4TranslateZ3D(0.0),
752 sprintf(name,
"BKLM.Layer%02d%sGapSolid", layer, (hasChimney ?
"Chimney" :
""));
755 gapHalfSize.x(), gapHalfSize.y(), gapHalfSize.z()
759 sprintf(name,
"BKLM.Layer%02d%s%sGapLogical", layer, (isFlipped ?
"Flipped" :
""), (hasChimney ?
"Chimney" :
""));
767 double dx = (
m_GeoPar->getModuleMiddleRadius(layer) -
m_GeoPar->getGapMiddleRadius(layer)) * CLHEP::cm;
771 int s2 =
m_GeoPar->getNSector() / 2;
774 }
else if (s1 > s2) {
777 double dz = moduleHalfSize.z() - gapHalfSize.z();
779 new G4PVPlacement(G4Translate3D(dx, 0.0, dz) * G4RotateZ3D(isFlipped ? M_PI : 0.0) * displacedGeo,
787 dz = gapHalfSize.z() - 0.5 *
m_GeoPar->getGapLength() * CLHEP::cm;
788 new G4PVPlacement(G4Translate3D(
m_GeoPar->getGapMiddleRadius(layer) * CLHEP::cm, 0.0, dz),
802 sprintf(name,
"BKLM.Layer%02d%sElectrodeSolid", layer, (hasChimney ?
"Chimney" :
""));
803 const CLHEP::Hep3Vector electrodeHalfSize =
m_GeoPar->getElectrodeHalfSize(layer, hasChimney) * CLHEP::cm;
804 G4Box* electrodeBox =
806 electrodeHalfSize.x(), electrodeHalfSize.y(), electrodeHalfSize.z()
808 G4LogicalVolume* electrodeLogical =
809 new G4LogicalVolume(electrodeBox,
815 sprintf(name,
"BKLM.Layer%02d%sGasSolid", layer, (hasChimney ?
"Chimney" :
""));
816 const CLHEP::Hep3Vector gasHalfSize =
m_GeoPar->getGasHalfSize(layer, hasChimney) * CLHEP::cm;
819 gasHalfSize.x(), gasHalfSize.y(), gasHalfSize.z()
821 G4LogicalVolume* gasLogical =
822 new G4LogicalVolume(gasBox,
832 new G4PVPlacement(G4TranslateX3D(-0.5 * electrodeHalfSize.x()),
841 new G4PVPlacement(G4TranslateX3D(+0.5 * electrodeHalfSize.x()),
849 new G4PVPlacement(G4TranslateZ3D(0.0),
862 sprintf(name,
"BKLM.Layer%02d%sAirSolid", layer, (hasChimney ?
"Chimney" :
""));
863 const CLHEP::Hep3Vector airHalfSize =
m_GeoPar->getAirHalfSize(layer, hasChimney) * CLHEP::cm;
866 airHalfSize.x(), airHalfSize.y(), airHalfSize.z()
868 G4LogicalVolume* airLogical =
869 new G4LogicalVolume(airBox,
874 sprintf(name,
"BKLM.Layer%02d%sScintEnvelopeSolid", layer, (hasChimney ?
"Chimney" :
""));
875 double mppcHousingHalfLength =
m_GeoPar->getMPPCHousingHalfLength() * CLHEP::cm;
876 const CLHEP::Hep3Vector envelopeHalfSize =
m_GeoPar->getScintEnvelopeHalfSize(layer, hasChimney) * CLHEP::cm +
877 CLHEP::Hep3Vector(0.0, mppcHousingHalfLength, mppcHousingHalfLength);
878 G4Box* scintEnvelopeBox =
880 envelopeHalfSize.x(), envelopeHalfSize.y(), envelopeHalfSize.z()
882 G4LogicalVolume* innerEnvelopeLogical =
883 new G4LogicalVolume(scintEnvelopeBox,
888 double scintHalfHeight =
m_GeoPar->getScintHalfHeight() * CLHEP::cm;
889 double scintHalfWidth =
m_GeoPar->getScintHalfWidth() * CLHEP::cm;
891 int envelopeOffsetSign =
m_GeoPar->getScintEnvelopeOffsetSign(layer);
893 for (
int scint = 1; scint <=
m_GeoPar->getNPhiScints(layer); ++scint) {
894 double scintHalfLength =
module->getPhiScintHalfLength(scint) * CLHEP::cm;
895 double scintPosition =
module->getPhiScintPosition(scint) * CLHEP::cm;
896 G4LogicalVolume* scintLogical =
getScintLogical(scintHalfHeight, scintHalfWidth, scintHalfLength,
897 mppcHousingHalfLength);
898 new G4PVPlacement(G4Translate3D(0.0, scintPosition + mppcHousingHalfLength * envelopeOffsetSign, 0.0),
901 innerEnvelopeLogical,
907 G4LogicalVolume* outerEnvelopeLogical =
908 new G4LogicalVolume(scintEnvelopeBox,
913 for (
int scint = 1; scint <=
m_GeoPar->getNZScints(hasChimney); ++scint) {
914 double scintHalfLength =
module->getZScintHalfLength(scint) * CLHEP::cm;
915 double scintOffset =
module->getZScintOffset(scint) * CLHEP::cm;
916 double scintPosition =
module->getZScintPosition(scint) * CLHEP::cm;
917 G4LogicalVolume* scintLogical =
getScintLogical(scintHalfHeight, scintHalfWidth, scintHalfLength,
918 mppcHousingHalfLength);
919 new G4PVPlacement(G4Translate3D(0.0, scintOffset, scintPosition - mppcHousingHalfLength) * G4RotateX3D(M_PI_2 * envelopeOffsetSign),
922 outerEnvelopeLogical,
928 CLHEP::Hep3Vector envelopeOffset =
m_GeoPar->getScintEnvelopeOffset(layer, hasChimney) * CLHEP::cm +
929 CLHEP::Hep3Vector(0.0, -mppcHousingHalfLength, mppcHousingHalfLength);
930 new G4PVPlacement(G4Translate3D(-envelopeHalfSize.x(), envelopeOffset.y() * envelopeOffsetSign, envelopeOffset.z()),
931 innerEnvelopeLogical,
938 new G4PVPlacement(G4Translate3D(+envelopeHalfSize.x(), envelopeOffset.y() * envelopeOffsetSign, envelopeOffset.z()),
939 outerEnvelopeLogical,
948 double containerHalfSizeZ =
m_GeoPar->getReadoutContainerHalfSize().z() * CLHEP::cm;
950 for (
int station = 1; station <=
m_GeoPar->getNReadoutStation(); ++station) {
951 double stationPosition =
m_GeoPar->getReadoutStationPosition(station) * CLHEP::cm;
953 if (
m_GeoPar->getReadoutStationIsPhi(station)) {
954 xform = G4Translate3D(0.0, stationPosition, airHalfSize.z() - containerHalfSizeZ);
956 xform = G4Translate3D(0.0,
957 (containerHalfSizeZ - airHalfSize.y()) * envelopeOffsetSign,
958 airHalfSize.z() + stationPosition
959 ) * G4RotateX3D(M_PI_2 * envelopeOffsetSign);
961 if (fabs(xform.getTranslation().z()) > airHalfSize.z())
964 sprintf(name,
"BKLM.ReadoutContainer%dLayer%02d%sPhysical", station, layer, (hasChimney ?
"Chimney" :
""));
965 new G4PVPlacement(xform,
966 readoutContainerLogical,
976 new G4PVPlacement(G4TranslateX3D(
m_GeoPar->getPolystyreneOffsetX() * CLHEP::cm),
991 G4Box* box = (G4Box*)(logicalVolume->GetSolid());
992 if ((std::fabs(box->GetXHalfLength() - dx) < 1.0E-4 * CLHEP::cm) &&
993 (std::fabs(box->GetYHalfLength() - dy) < 1.0E-4 * CLHEP::cm) &&
994 (std::fabs(box->GetZHalfLength() - dz - dzMPPC) < 1.0E-4 * CLHEP::cm)) {
995 return logicalVolume;
1000 sprintf(name,
"BKLM.ScintType%dSolid", newLvol);
1001 G4Box* scintBox =
new G4Box(name, dx, dy, dz + dzMPPC);
1002 G4LogicalVolume* scintLogical =
1006 sprintf(name,
"BKLM.ScintType%dAirSolid", newLvol);
1007 G4Box* scintAirBox =
new G4Box(name, dx, dy, dzMPPC);
1008 G4LogicalVolume* scintAirLogical =
1011 double dxTiO2 =
m_GeoPar->getScintTiO2ThicknessTop() * CLHEP::cm;
1012 double dyTiO2 =
m_GeoPar->getScintTiO2ThicknessSide() * CLHEP::cm;
1013 sprintf(name,
"BKLM.ScintActiveType%dSolid", newLvol);
1014 G4Box* activeBox =
new G4Box(name, dx - dxTiO2, dy - dyTiO2, dz);
1015 G4LogicalVolume* activeLogical =
1020 sprintf(name,
"BKLM.ScintBoreType%dSolid", newLvol);
1021 G4Tubs* boreTube =
new G4Tubs(name, 0.0,
m_GeoPar->getScintBoreRadius() * CLHEP::cm, dz, 0.0, 2.0 * M_PI);
1022 G4LogicalVolume* scintBoreLogical =
1025 sprintf(name,
"BKLM.ScintFiberType%dSolid", newLvol);
1026 G4Tubs* fiberTube =
new G4Tubs(name, 0.0,
m_GeoPar->getScintFiberRadius() * CLHEP::cm, dz, 0.0, 2.0 * M_PI);
1027 G4LogicalVolume* scintFiberLogical =
new G4LogicalVolume(fiberTube,
Materials::get(
"G4_POLYSTYRENE"),
logicalName(fiberTube));
1031 new G4PVPlacement(G4TranslateZ3D(0.0),
1039 new G4PVPlacement(G4TranslateZ3D(0.0),
1047 new G4PVPlacement(G4TranslateZ3D(-dzMPPC),
1055 new G4PVPlacement(G4TranslateZ3D(0.0),
1057 "BKLM.MPPCHousingPhysical",
1063 new G4PVPlacement(G4TranslateZ3D(dz),
1071 return scintLogical;
1077 G4Tubs* mppcHousingSolid =
1078 new G4Tubs(
"BKLM.MPPCHousingSolid",
1080 m_GeoPar->getMPPCHousingRadius() * CLHEP::cm,
1081 m_GeoPar->getMPPCHousingHalfLength() * CLHEP::cm,
1086 new G4LogicalVolume(mppcHousingSolid,
1088 "BKLM>MPPCHousingLogical"
1094 new G4Box(
"BKLM.MPPCSolid",
1095 m_GeoPar->getMPPCHalfLength() * CLHEP::cm,
1096 m_GeoPar->getMPPCHalfWidth() * CLHEP::cm,
1097 m_GeoPar->getMPPCHalfHeight() * CLHEP::cm
1099 G4LogicalVolume* mppcLogical =
1100 new G4LogicalVolume(mppcBox,
1107 new G4PVPlacement(G4TranslateX3D(0.0),
1109 "BKLM.MPPCPhysical",
1122 const CLHEP::Hep3Vector containerHalfSize =
m_GeoPar->getReadoutContainerHalfSize() * CLHEP::cm;
1123 G4Box* containerBox =
1124 new G4Box(
"BKLM.ReadoutContainerSolid",
1125 containerHalfSize.x(), containerHalfSize.y(), containerHalfSize.z()
1128 new G4LogicalVolume(containerBox,
1134 const CLHEP::Hep3Vector carrierHalfSize =
m_GeoPar->getReadoutCarrierHalfSize() * CLHEP::cm;
1136 new G4Box(
"BKLM.ReadoutCarrierSolid",
1137 carrierHalfSize.x(), carrierHalfSize.y(), carrierHalfSize.z()
1139 G4LogicalVolume* carrierLogical =
1140 new G4LogicalVolume(carrierBox,
1147 const CLHEP::Hep3Vector preamplifierHalfSize =
m_GeoPar->getReadoutPreamplifierHalfSize() * CLHEP::cm;
1148 G4Box* preamplifierBox =
1149 new G4Box(
"BKLM.ReadoutPreamplifierSolid",
1150 preamplifierHalfSize.x(), preamplifierHalfSize.y(), preamplifierHalfSize.z()
1152 G4LogicalVolume* preamplifierLogical =
1153 new G4LogicalVolume(preamplifierBox,
1158 const CLHEP::Hep3Vector connectorsHalfSize =
m_GeoPar->getReadoutConnectorsHalfSize() * CLHEP::cm;
1159 G4Box* connectorsBox =
1160 new G4Box(
"BKLM.ReadoutConnectorsSolid",
1161 connectorsHalfSize.x(), connectorsHalfSize.y(), connectorsHalfSize.z()
1163 G4LogicalVolume* connectorsLogical =
1164 new G4LogicalVolume(connectorsBox,
1171 new G4PVPlacement(G4TranslateZ3D(preamplifierHalfSize.z()),
1179 new G4PVPlacement(G4Translate3D(0.0,
m_GeoPar->getReadoutConnectorsPosition(), -carrierHalfSize.z()),
1187 for (
int preamp = 1; preamp <=
m_GeoPar->getNReadoutPreamplifierPosition(); ++preamp) {
1188 new G4PVPlacement(G4Translate3D(0.0,
1189 m_GeoPar->getReadoutPreamplifierPosition(preamp) * CLHEP::cm,
1190 -carrierHalfSize.z()),
1191 preamplifierLogical,
1208 new G4Tubs(
"BKLM.SolenoidTube",
1210 m_GeoPar->getSolenoidOuterRadius() * CLHEP::cm,
1211 2.0 *
m_GeoPar->getHalfLength() * CLHEP::cm,
1221 G4String* name =
new G4String(solid->GetName().substr(0, solid->GetName().size() - 5) +
"Logical");
1228 G4String* name =
new G4String(lvol->GetName().substr(0, lvol->GetName().size() - 7) +
"Physical");
@ c_ChimneySector
Chimney sector: BB3 in 1-based notation; BB2 in 0-based notation.
static constexpr int getMaximalLayerNumber()
Get maximal layer number (1-based).
@ c_ForwardSection
Forward.
@ c_BackwardSection
Backward.
static constexpr int getMaximalSectorNumber()
Get maximal sector number (1-based).
The Class for BKLM geometry.
KLM sensitive-detector class.
void putLayer1SupportInInnerVoid(G4LogicalVolume *, bool)
Put the layer-0 support plate into the inner region's air void (sectors 1..5 only)
void putChimneyInLayer(G4LogicalVolume *, int)
Put the solenoid's cooling chimney into the backward top sector.
G4LogicalVolume * m_LayerGapLogical[12 *BKLMElementNumbers::getMaximalLayerNumber()]
Pointers to logical volumes for air gap in each layer [side/bottom/top | isFlipped | hasChimney | lay...
G4LogicalVolume * m_SupportLogical[2]
Pointer to logical volumes for support structure [hasChimney].
G4Tubs * m_SolenoidTube
Pointer to solid for solenoid.
G4LogicalVolume * m_ReadoutContainerLogical
Pointer to logical volume for scint preamplifier/carrier container.
void putScintsInInterior(G4LogicalVolume *, int, int, int, bool)
Put the scintillators into each detector module's interior (module is itself in an air gap)
G4LogicalVolume * m_BracketLogical
Pointer to logical volume for bracket.
G4Polyhedra * m_CapSolid
Pointer to solid for cap.
G4LogicalVolume * m_SectorLogical[2][BKLMElementNumbers::getMaximalSectorNumber()]
Pointers to logical volumes for each sector [fb-1][sector-1].
void createGeometry(const BKLMGeometryPar ¶meters, G4LogicalVolume &topVolume, geometry::GeometryTypes type)
Create the geometry from a parameter object.
double m_SectorDphi
Angular extent of one sector.
G4Tubs * m_SectorTube
Pointer to solid for sector's enclosing tube.
~GeoBKLMCreator()
Destructor of the GeoBKLMCreator class.
void putEndsInEnvelope(G4LogicalVolume *)
Put the forward and backward ends into the BKLM envelope.
G4Box * m_LayerGapSolid[2 *BKLMElementNumbers::getMaximalLayerNumber()]
Pointers to solids for air gap in each layer [hasChimney | layer-1].
double m_RibShift
Radial displacement of polygon to create an azimuthal iron rib.
G4LogicalVolume * getReadoutContainerLogical(void)
Get pointer to readout-container logical volume.
void putLayersInSector(G4LogicalVolume *, int, int, bool)
Put the layers into each sector.
std::vector< G4VisAttributes * > m_VisAttributes
Vector of pointers to G4VisAttributes objects.
G4LogicalVolume * m_MPPCHousingLogical
Pointer to logical volume for MPPC housing.
GeoBKLMCreator()
Constructor of the GeoBKLMCreator class.
G4VSolid * m_InnerIronSolid
Pointer to solid for inner iron [hasInnerSupport | hasChimney].
void putSectorsInEnd(G4LogicalVolume *, int)
Put each sector into the forward or backward end.
G4Tubs * getSolenoidTube(void)
Get shape corresponding to the solenoid (for subtraction)
double m_SectorDz
Half-length of one sector.
G4Polyhedra * m_LayerIronSolid[BKLMElementNumbers::getMaximalLayerNumber()]
Pointers to solids for iron in each layer [layer-1].
G4LogicalVolume * m_InnerAirLogical[4]
Pointer to logical volumes for inner air [hasInnerSupport | hasChimney].
G4LogicalVolume * m_CapLogical[2]
Pointer to logical volumes for cap [hasChimney].
void putCapInSector(G4LogicalVolume *, bool)
Put the cap (at maximum |z|) into each sector.
G4LogicalVolume * m_InnerIronLogical[4]
Pointer to logical volumes for inner iron [hasInnerSupport | hasChimney].
void putVoidInInnerRegion(G4LogicalVolume *, bool, bool)
Put the air void into the inner-radius region.
G4String logicalName(G4VSolid *)
convert G4VSolid's name to corresponding G4LogicalVolume name
G4VSensitiveDetector * m_Sensitive
Pointer to the BKLM SensitiveDetector processor.
G4LogicalVolume * getScintLogical(double, double, double, double)
Get pointer to scintillator logical volume.
std::vector< G4LogicalVolume * > m_ScintLogicals
Pointers to logical volumes for scintillator strips.
G4LogicalVolume * m_LayerIronLogical[12 *BKLMElementNumbers::getMaximalLayerNumber()]
Pointers to logical volumes for iron in each layer [side/bottom/top | isFlipped | hasChimney | layer-...
GeometryPar * m_GeoPar
Pointer to the BKLM geometry accessor.
G4String physicalName(G4LogicalVolume *)
convert G4LogicalVolume's name to corresponding G4PhysicalVolume name
void putRPCsInInterior(G4LogicalVolume *, int, bool)
Put the RPCs into each detector module's interior (module is itself in an air gap)
void putModuleInLayer(G4LogicalVolume *, int, int, int, bool, bool, int)
Put the module (and enclosing air gap) into each layer.
void putLayer1BracketsInInnerVoid(G4LogicalVolume *, bool)
Put the layer-0 support plate's brackets into the inner region's air void (sectors 1....
void putInnerRegionInSector(G4LogicalVolume *, bool, bool)
Put the inner-radius region into each sector.
G4VSolid * m_InnerAirSolid
Pointer to solid for inner air.
std::vector< G4String * > m_Names
Vector of pointers to G4String objects (volume names)
G4LogicalVolume * getMPPCHousingLogical(void)
Get pointer to MPPC-container logical volume.
G4LogicalVolume * m_LayerModuleLogical[2 *BKLMElementNumbers::getMaximalLayerNumber()]
Pointers to logical volumes for detector modules in each layer's air gap [hasChimney | layer-1].
static GeometryPar * instance(void)
Static method to get a reference to the singleton GeometryPar instance.
Define the geometry of a BKLM module Each sector [octant] contains Modules.
static G4Material * get(const std::string &name)
Find given material.
double tan(double a)
tan for double
Common code concerning the geometry representation of the detector.
GeometryTypes
Flag indicating the type of geometry to be used.