// M Hentz, 2016 #include "DetectorConstruction.hh" #include "DetectorMessenger.hh" #include "G4Material.hh" #include "G4Box.hh" #include "G4Tubs.hh" #include "G4LogicalVolume.hh" #include "G4PVPlacement.hh" #include "G4PVReplica.hh" #include "G4UnionSolid.hh" #include "G4SubtractionSolid.hh" #include "G4Transform3D.hh" #include "G4VisAttributes.hh" #include "G4PhysicalVolumeStore.hh" #include "G4LogicalVolumeStore.hh" #include "G4SolidStore.hh" #include "G4GeometryManager.hh" #include "G4TransportationManager.hh" #include "G4RunManager.hh" #include "G4NistManager.hh" #include "G4UnitsTable.hh" #include "G4PhysicalConstants.hh" #include "G4SystemOfUnits.hh" DetectorConstruction::DetectorConstruction() :G4VUserDetectorConstruction(), fWorldMaterial(0), fAbsorMaterial(0), lAbsor(0), fDetectorMessenger(0) { fWorldSizeX = fWorldSizeZ = 9450.*CLHEP::mm; fWorldSizeY = 4450.*CLHEP::mm; fWorldMaterial = 0; fRoomSizeX = 8000.*CLHEP::mm; fRoomSizeY = 3400.*CLHEP::mm; fRoomSizeZ = 8400.*CLHEP::mm; fAbsorSizeXY = 40.*CLHEP::mm; fAbsorSizeZ = 40.*CLHEP::mm; fAbsorMaterial = 0; lAbsor = 0; detSizeXY = fAbsorSizeXY + 5.*CLHEP::mm; detSizeZ = fAbsorSizeZ + 5.*CLHEP::mm; fLayerNumber = 0; fLayerMass = 0; fLayerSizeXY = 20.*CLHEP::mm; fLayerSizeZ = 0.*CLHEP::mm; DefineMaterials(); // Create commands for interactive definition of the detector fDetectorMessenger = new DetectorMessenger( this ); } DetectorConstruction::~DetectorConstruction() { delete fDetectorMessenger; } G4VPhysicalVolume* DetectorConstruction::Construct() { return ConstructVolumes(); } void DetectorConstruction::DefineMaterials() { // Use G4NistManager if material from NIST database is needed // G4NistManager* nistMan = G4NistManager::Instance(); //------------------------------------------------------------------------------------ // Define elements //------------------------------------------------------------------------------------ G4double z, a; G4Element* H = new G4Element( "Hydrogen" , "H" , z=1 , a=1.008 *CLHEP::g/CLHEP::mole ); G4Element* Li = new G4Element( "Lithium" , "Li", z=3 , a=6.941 *CLHEP::g/CLHEP::mole ); G4Element* B = new G4Element( "Boron" , "B" , z=5 , a=10.81 *CLHEP::g/CLHEP::mole ); G4Element* C = new G4Element( "Carbon" , "C" , z=6 , a=12.01 *CLHEP::g/CLHEP::mole ); G4Element* N = new G4Element( "Nitrogen" , "N" , z=7 , a=14.01 *CLHEP::g/CLHEP::mole ); G4Element* O = new G4Element( "Oxygen" , "O" , z=8 , a=16.00 *CLHEP::g/CLHEP::mole ); G4Element* Na = new G4Element( "Sodium" , "Na", z=11, a=22.99 *CLHEP::g/CLHEP::mole ); G4Element* Mg = new G4Element( "Magnesium", "Mg", z=12, a=24.305 *CLHEP::g/CLHEP::mole ); G4Element* Al = new G4Element( "Aluminium", "Al", z=13, a=26.98 *CLHEP::g/CLHEP::mole ); G4Element* Si = new G4Element( "Silicon" , "Si", z=14, a=28.09 *CLHEP::g/CLHEP::mole ); G4Element* Ar = new G4Element( "Argon" , "Ar", z=18, a=39.948 *CLHEP::g/CLHEP::mole ); G4Element* Ca = new G4Element( "Calcium" , "Ca", z=20, a=40.08 *CLHEP::g/CLHEP::mole ); G4Element* Fe = new G4Element( "Iron" , "Fe", z=26, a=55.85 *CLHEP::g/CLHEP::mole ); G4Element* Co = new G4Element( "Cobalt" , "Co", z=27, a=58.933 *CLHEP::g/CLHEP::mole ); G4Element* Cu = new G4Element( "Copper" , "Cu", z=29, a=63.546 *CLHEP::g/CLHEP::mole ); G4Element* Zn = new G4Element( "Zinc" , "Zn", z=30, a=65.38 *CLHEP::g/CLHEP::mole ); G4Element* Eu = new G4Element( "Europium" , "Eu", z=63, a=151.964 *CLHEP::g/CLHEP::mole ); G4Element* Cs = new G4Element( "Caesium" , "Cs", z=55, a=132.905 *CLHEP::g/CLHEP::mole ); G4Element* W = new G4Element( "Tungsten" , "W" , z=74, a=183.84 *CLHEP::g/CLHEP::mole ); //------------------------------------------------------------------------------------ // Define materials //------------------------------------------------------------------------------------ G4double density, temperature, pressure, fractionmass; G4int natoms, ncomponents; // Vacuum density = universe_mean_density; // from PhysicalConstants.h pressure = 3.e-18*pascal; temperature = 2.73*kelvin; fVacuum = new G4Material( "Vacuum", z=1, a=1.008*g/mole, density, kStateGas, temperature, pressure ); fAir = new G4Material( "Air", density=1.290*CLHEP::mg/CLHEP::cm3, ncomponents=3 ); fAir->AddElement( N, fractionmass=0.7810 ); // 78.10% fAir->AddElement( O, fractionmass=0.2096 ); // 20.96% fAir->AddElement( Ar, fractionmass=0.0094 ); // 0.94% fWater = new G4Material( "Water", density=1.*CLHEP::g/CLHEP::cm3, ncomponents=2 ); fWater->AddElement( H, natoms=2 ); fWater->AddElement( O, natoms=1 ); fWater->GetIonisation()->SetMeanExcitationEnergy( 78.0*eV ); fScintillatorPVT = new G4Material( "Scintillator_PVT", density=1.023*CLHEP::g/CLHEP::cm3, ncomponents=2 ); fScintillatorPVT->AddElement( C, natoms=9 ); fScintillatorPVT->AddElement( H, natoms=10 ); fMarbleConcrete = new G4Material( "MarbleConcrete", density=2.7*CLHEP::g/CLHEP::cm3, ncomponents=12 ); fMarbleConcrete->AddElement( Ca, fractionmass=0.473942 ); // 47.3942% fMarbleConcrete->AddElement( O, fractionmass=0.375 ); // 37.5% fMarbleConcrete->AddElement( C, fractionmass=0.105 ); // 10.5% fMarbleConcrete->AddElement( Si, fractionmass=0.024 ); // 2.4% fMarbleConcrete->AddElement( Fe, fractionmass=0.01 ); // 1% fMarbleConcrete->AddElement( Al, fractionmass=0.007 ); // 0.7% fMarbleConcrete->AddElement( Mg, fractionmass=0.003 ); // 0.3% fMarbleConcrete->AddElement( Na, fractionmass=0.002 ); // 0.2% fMarbleConcrete->AddElement( Li, fractionmass=0.000037 ); // 37 ppm fMarbleConcrete->AddElement( Co, fractionmass=0.000018 ); // 18 ppm fMarbleConcrete->AddElement( Cs, fractionmass=0.000002 ); // 2 ppm fMarbleConcrete->AddElement( Eu, fractionmass=0.000001 ); // 1 ppm fAluminium = new G4Material( "Aluminium", density=2.7*CLHEP::g/CLHEP::cm3, ncomponents=1 ); fAluminium->AddElement( Al, fractionmass=1 ); fBrass = new G4Material( "Brass", density=8.75*CLHEP::g/CLHEP::cm3, ncomponents=2 ); fBrass->AddElement( Cu, fractionmass=0.7 ); // 70% fBrass->AddElement( Zn, fractionmass=0.3 ); // 30% fTungsten = new G4Material( "Tungsten", density=19.25*CLHEP::g/CLHEP::cm3, ncomponents=1 ); fTungsten->AddElement( W, fractionmass=1. ); fKapton = new G4Material( "Kapton", density=1.42*CLHEP::g/CLHEP::cm3, ncomponents=4 ); fKapton->AddElement( H, fractionmass=0.027 ); // 2.7% fKapton->AddElement( C, fractionmass=0.691 ); // 69.1% fKapton->AddElement( N, fractionmass=0.073 ); // 7.3% fKapton->AddElement( O, fractionmass=0.209 ); // 20.9% fIron = new G4Material( "Iron", density=7.874*CLHEP::g/CLHEP::cm3, ncomponents=1 ); fIron->AddElement( Fe, fractionmass=1. ); fPMMA = new G4Material( "PMMA", density=1.18*CLHEP::g/CLHEP::cm3, ncomponents=3 ); fPMMA->AddElement( C, natoms=5 ); fPMMA->AddElement( O, natoms=2 ); fPMMA->AddElement( H, natoms=8 ); fMylar = new G4Material( "Mylar", density=1.397*CLHEP::g/CLHEP::cm3, ncomponents=3 ); fMylar->AddElement( C, natoms=10 ); fMylar->AddElement( H, natoms=8 ); fMylar->AddElement( O, natoms=4 ); // 5% borated polyethylene fBoratedPlastic = new G4Material( "BoratedPlastic", density=1.04*CLHEP::g/CLHEP::cm3, ncomponents=3 ); fBoratedPlastic->AddElement( B, fractionmass=0.05 ); fBoratedPlastic->AddElement( C, fractionmass=0.317 ); fBoratedPlastic->AddElement( H, fractionmass=0.633 ); //------------------------------------------------------------------------------------ // Default materials //------------------------------------------------------------------------------------ fWorldMaterial = fAir; fAbsorMaterial = fScintillatorPVT; } G4VPhysicalVolume* DetectorConstruction::ConstructVolumes() { G4GeometryManager::GetInstance()->OpenGeometry(); G4PhysicalVolumeStore::GetInstance()->Clean(); G4LogicalVolumeStore::GetInstance()->Clean(); G4SolidStore::GetInstance()->Clean(); G4bool checkOverlaps = true; // For G4Tubs objects G4double startAngle = 0; G4double spanningAngle = 2.*CLHEP::pi; // Set visAttributes for various components G4VisAttributes* invisibleVisAtt = new G4VisAttributes( false ); G4VisAttributes* wireframeVisAtt = new G4VisAttributes(); wireframeVisAtt->SetForceWireframe( true ); G4VisAttributes* mylarVisAtt = new G4VisAttributes( G4Colour( 1., 1., 0., 0.1 ) ); G4VisAttributes* perspexVisAtt = new G4VisAttributes( G4Colour( 1., 1., 1., 0.25 ) ); G4VisAttributes* brassVisAtt = new G4VisAttributes( G4Colour( 0.71, 0.651, 0.259, 1. ) ); G4VisAttributes* wiresVisAtt = new G4VisAttributes( G4Colour( 0., 0., 0. ) ); // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % // --->>> ROOM <<<--- // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % // World // - G4Box needs to be supplied half-lengths G4Box* sWorld = new G4Box( "World", fWorldSizeX/2, fWorldSizeY/2, fWorldSizeZ/2 ); G4LogicalVolume* lWorld = new G4LogicalVolume( sWorld, fWorldMaterial, "World" ); G4VPhysicalVolume* pWorld = new G4PVPlacement( 0, G4ThreeVector(), lWorld, "World", 0, false, 0 ); lWorld->SetVisAttributes( wireframeVisAtt ); // Outer room // - Concrete box to emulate scattering from ceiling, floor and walls sRoomOut = new G4Box( "Walls", 8150.*CLHEP::mm/2, 3550.*CLHEP::mm/2, 8550.*CLHEP::mm/2 ); lRoomOut = new G4LogicalVolume( sRoomOut, fMarbleConcrete, "Walls" ); pRoomOut = new G4PVPlacement( 0, G4ThreeVector(), lRoomOut, "Walls", lWorld, false, 0, checkOverlaps ); lRoomOut->SetVisAttributes( wireframeVisAtt ); // Inner room sRoomIn = new G4Box( "Room", fRoomSizeX/2, fRoomSizeY/2, fRoomSizeZ/2 ); lRoomIn = new G4LogicalVolume( sRoomIn, fAir, "Room" ); pRoomIn = new G4PVPlacement( 0, G4ThreeVector(), lRoomIn, "Room", lRoomOut, false, 0, checkOverlaps ); lRoomIn->SetVisAttributes( wireframeVisAtt ); // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % // --->>> BEAM LINE <<<--- // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % // --> section 1 <-- // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % //------------------------------------------------------------------------------------ // Aluminium tube // Position relative to room: z = -4200 + 356/2 mm // - Place a smaller cylinder insider a larger one to create vacuum //------------------------------------------------------------------------------------ // Outer cylinder (aluminium) sAlTube1Out = new G4Tubs( "AlTube1Out", 0., 38.*CLHEP::mm, 356.*CLHEP::mm/2,startAngle, spanningAngle ); lAlTube1Out = new G4LogicalVolume( sAlTube1Out, fAluminium, "AlTube1Out" ); pAlTube1Out = new G4PVPlacement( 0, G4ThreeVector(0., 0., -4022.*CLHEP::mm), lAlTube1Out, "AlTube1Out", lRoomIn, false, 0, checkOverlaps ); lAlTube1Out->SetVisAttributes( wireframeVisAtt ); // Inner cylinder (vacuum) sAlTube1In = new G4Tubs( "AlTube1In", 0., 36.*CLHEP::mm, 356.*CLHEP::mm/2, startAngle, spanningAngle ); lAlTube1In = new G4LogicalVolume( sAlTube1In, fVacuum, "AlTube1In" ); pAlTube1In = new G4PVPlacement( 0, G4ThreeVector(), lAlTube1In, "AlTube1In", lAlTube1Out, false, 0, checkOverlaps ); lAlTube1In->SetVisAttributes( wireframeVisAtt ); //------------------------------------------------------------------------------------ // Particle source // Position relative to tube: z = -356/2 + 0 mm // - The GerealParticleSource is confined to this volume in PrimaryGeneratorAction.cc //------------------------------------------------------------------------------------ sSource = new G4Tubs( "Source", 0., 30.*CLHEP::mm, 1.*CLHEP::mm/2, startAngle, spanningAngle ); lSource = new G4LogicalVolume( sSource, fVacuum, "Source" ); pSource = new G4PVPlacement( 0, G4ThreeVector(0., 0., -177.5*CLHEP::mm), lSource, "Source", lAlTube1In, false, 0, checkOverlaps ); lSource->SetVisAttributes( invisibleVisAtt ); //------------------------------------------------------------------------------------ // 1st collimator // Position relative to tube: z = -356/2 + 55 mm //------------------------------------------------------------------------------------ sCollimator1 = new G4Tubs( "Collimator1", 3.*CLHEP::mm, 36.*CLHEP::mm, 10.*CLHEP::mm/2, startAngle, spanningAngle ); lCollimator1 = new G4LogicalVolume( sCollimator1, fBrass, "Collimator1" ); pCollimator1 = new G4PVPlacement( 0, G4ThreeVector(0., 0., -123.*CLHEP::mm), lCollimator1, "Collimator1", lAlTube1In, false, 0, checkOverlaps ); //------------------------------------------------------------------------------------ // 1st scatter foil // Position relative to tube: z = -356/2 + 80 + 0.025/2 mm //------------------------------------------------------------------------------------ sScatterFoil1 = new G4Tubs( "ScatterFoil1", 0., 36.*CLHEP::mm, 0.025*CLHEP::mm/2, startAngle, spanningAngle ); lScatterFoil1 = new G4LogicalVolume( sScatterFoil1, fTungsten, "ScatterFoil1" ); pScatterFoil1 = new G4PVPlacement( 0, G4ThreeVector(0., 0., -97.9875*CLHEP::mm), lScatterFoil1, "ScatterFoil1", lAlTube1In, false, 0, checkOverlaps ); lScatterFoil1->SetVisAttributes( wireframeVisAtt ); //------------------------------------------------------------------------------------ // Beam stopper // Position relative to tube: z = -356/2 + 300 + 6.6/2 mm //------------------------------------------------------------------------------------ // Rotation matrix to adjust the orientation of the stopper if needed G4RotationMatrix* stopperOffset = new G4RotationMatrix(); G4double stopperOffsetAngle = 0.*CLHEP::deg; stopperOffset->rotateY( stopperOffsetAngle/CLHEP::rad ); sStopper = new G4Tubs( "Stopper", 0., 2.855*CLHEP::mm, 6.6*CLHEP::mm/2, startAngle, spanningAngle ); lStopper= new G4LogicalVolume( sStopper, fBrass, "Stopper" ); pStopper = new G4PVPlacement( stopperOffset, G4ThreeVector(0., 0., 125.3*CLHEP::mm), lStopper, "Stopper", lAlTube1In, false, 0, checkOverlaps ); //------------------------------------------------------------------------------------ // 2nd scatter foil // Position relative to tube: z = -356/2 + 306.6 + 0.025/2 mm // - Replicate 1st scatter foil at different position //------------------------------------------------------------------------------------ pScatterFoil2 = new G4PVPlacement( 0, G4ThreeVector(0., 0., 128.6125*CLHEP::mm), lScatterFoil1, "ScatterFoil2", lAlTube1In, false, 0, checkOverlaps ); //------------------------------------------------------------------------------------ // Kapton window // Position relative to tube: z = -4200 + 356 + 0.05/2 mm //------------------------------------------------------------------------------------ sKaptonWindow = new G4Tubs( "Kapton", 0., 36*CLHEP::mm, 0.05*CLHEP::mm/2, startAngle, spanningAngle ); lKaptonWindow = new G4LogicalVolume( sKaptonWindow, fKapton, "Kapton" ); pKaptonWindow = new G4PVPlacement( 0, G4ThreeVector(0., 0., -3843.975*CLHEP::mm), lKaptonWindow, "Kapton", lRoomIn, false, 0, checkOverlaps ); // --> section 2 <-- // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % //------------------------------------------------------------------------------------ // Aluminium box // Position relative to room: z = -4200 + 550 mm // - Subtract smaller box from a larger one to create cavity //------------------------------------------------------------------------------------ // Volumes to be subtracted from each other sAlBox1Out = new G4Box( "AlBox1Out", 200*CLHEP::mm/2, 200*CLHEP::mm/2, 200*CLHEP::mm/2 ); sAlBox1In = new G4Box( "AlBox1In", 160*CLHEP::mm/2, 160*CLHEP::mm/2, 160*CLHEP::mm/2 ); // Create hollow box sAlBox1 = new G4SubtractionSolid( "AlBox1", sAlBox1Out, sAlBox1In ); lAlBox1 = new G4LogicalVolume( sAlBox1, fAluminium, "AlBox1" ); pAlBox1 = new G4PVPlacement( 0, G4ThreeVector(0., 0., -3650.*CLHEP::mm), lAlBox1, "AlBox1", lRoomIn, false, 0, !checkOverlaps ); lAlBox1->SetVisAttributes( wireframeVisAtt ); //------------------------------------------------------------------------------------ // Holes in box in beam direction //------------------------------------------------------------------------------------ // First hole // Position relative to box: z = -200/2 + 10 mm sAlBox1Hole1 = new G4Tubs( "AlBox1Hole1", 0., 36.*CLHEP::mm, 20.*CLHEP::mm/2, startAngle, spanningAngle ); lAlBox1Hole1 = new G4LogicalVolume( sAlBox1Hole1, fAir, "AlBox1Hole1" ); pAlBox1Hole1 = new G4PVPlacement( 0, G4ThreeVector(0., 0., -90.*CLHEP::mm), lAlBox1Hole1, "AlBox1Hole1", lAlBox1, false, 0, checkOverlaps ); lAlBox1Hole1->SetVisAttributes( wireframeVisAtt ); // Second hole // Position relative to box: z = -200/2 + 190 mm // - Replicate first hole in different position pAlBox1Hole2 = new G4PVPlacement( 0, G4ThreeVector(0., 0., 90.*CLHEP::mm), lAlBox1Hole1, "AlBox1Hole2", lAlBox1, false, 0, checkOverlaps); //------------------------------------------------------------------------------------ // Iron block // Position relative to room: z = -4200 + 662.5 mm // - Subtract cylinder from box to create a hole for the beam //------------------------------------------------------------------------------------ // Volumes to be subtracted from each other sIronBlockOut = new G4Box( "IronBlockOut", 220.*CLHEP::mm/2, 220.*CLHEP::mm/2, 25.*CLHEP::mm/2 ); sIronBlockIn = new G4Tubs( "IronBlockIn", 0., 38*CLHEP::mm, 25.*CLHEP::mm/2, startAngle, spanningAngle ); // Create block with hole sIronBlock = new G4SubtractionSolid( "IronBlock", sIronBlockOut, sIronBlockIn ); lIronBlock = new G4LogicalVolume( sIronBlock, fIron, "IronBlock" ); pIronBlock = new G4PVPlacement( 0, G4ThreeVector(0., 0., -3537.5*CLHEP::mm), lIronBlock, "IronBlock", lRoomIn, false, 0, checkOverlaps ); // --> section 3 <-- // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % //------------------------------------------------------------------------------------ // Aluminium tube // Position relative to room: z = -4200 + 875 mm //------------------------------------------------------------------------------------ sAlTube2 = new G4Tubs( "AlTube2", 36.*CLHEP::mm, 38.*CLHEP::mm, 450.*CLHEP::mm/2, startAngle, spanningAngle ); lAlTube2 = new G4LogicalVolume( sAlTube2, fAluminium, "AlTube2" ); pAlTube2 = new G4PVPlacement( 0, G4ThreeVector(0., 0., -3325.*CLHEP::mm), lAlTube2, "AlTube2", lRoomIn, false, 0, checkOverlaps ); // --> section 4 <-- // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % // % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % //------------------------------------------------------------------------------------ // Aluminium box // Position relative to room: z = -4200 + 1396 mm // - Subtract smaller box from a larger one to create cavity //------------------------------------------------------------------------------------ // Volumes to be subtracted from each other sAlBox2Out = new G4Box( "AlBox2Out", 200.*CLHEP::mm/2, 200.*CLHEP::mm/2, 592.*CLHEP::mm/2 ); sAlBox2In = new G4Box( "AlBox2In", 160.*CLHEP::mm/2, 160.*CLHEP::mm/2, 552.*CLHEP::mm/2 ); // Create hollow box sAlBox2Walls = new G4SubtractionSolid( "AlBox2Walls", sAlBox2Out, sAlBox2In ); //------------------------------------------------------------------------------------ // Holes in box in beam direction // - Subtract holes from aluminium box one by one //------------------------------------------------------------------------------------ // First hole // Position relative to box: z = -592/2 + 10 mm sAlBox2Hole1 = new G4Tubs( "AlBox2Hole1", 0., 36.*CLHEP::mm, 20.*CLHEP::mm/2, startAngle, spanningAngle ); sAlBox2WallsWith1Hole = new G4SubtractionSolid( "AlBox2WallsWith1Hole", sAlBox2Walls, sAlBox2Hole1, 0, G4ThreeVector(0., 0., -286.*CLHEP::mm) ); // Second hole // Position relative to box = z = -592/2 + 582 mm sAlBox2Hole2 = new G4Tubs( "AlBox2Hole2", 0., 20.*CLHEP::mm, 20.*CLHEP::mm/2, startAngle, spanningAngle ); sAlBox2WallsWith2Holes = new G4SubtractionSolid( "AlBox2WallsWith2Holes", sAlBox2WallsWith1Hole, sAlBox2Hole2, 0, G4ThreeVector(0., 0., 286.*CLHEP::mm) ); //------------------------------------------------------------------------------------ // Create logical volumes for the box with holes // and the volume of air inside the box and place the box //------------------------------------------------------------------------------------ lAlBox2WallsWith2Holes = new G4LogicalVolume( sAlBox2WallsWith2Holes, fAluminium, "AlBox2WallsWith2Holes" ); new G4PVPlacement( 0, G4ThreeVector(0., 0., -2804.*CLHEP::mm), lAlBox2WallsWith2Holes, "AlBox2WallsWith2Holes", lRoomIn, false, 0, checkOverlaps ); lAlBox2WallsWith2Holes->SetVisAttributes( wireframeVisAtt ); // Logical volume for the inside of the box lAlBox2 = new G4LogicalVolume( sAlBox2In, fAir, "AlBox2" ); new G4PVPlacement( 0, G4ThreeVector(0., 0., 0.), lAlBox2, "AlBox2", lAlBox2WallsWith2Holes, false, 0, checkOverlaps ); lAlBox2->SetVisAttributes( wireframeVisAtt ); //------------------------------------------------------------------------------------ // 2nd collimator // Position relative to box: z = -582/2 + 25 mm // - Add 0.002 mm to z dimension of inner part to fix visualisation //------------------------------------------------------------------------------------ sCollimator2Out = new G4Box( "Collimator2Out", 160.*CLHEP::mm/2, 160.*CLHEP::mm/2, 10.*CLHEP::mm/2 ); sCollimator2In = new G4Tubs( "Collimator2In", 0., 20.*CLHEP::mm, 10.002*CLHEP::mm/2, startAngle, spanningAngle ); sCollimator2 = new G4SubtractionSolid( "Collimator2", sCollimator2Out, sCollimator2In ); lCollimator2 = new G4LogicalVolume( sCollimator2, fBrass, "Collimator2" ); pCollimator2 = new G4PVPlacement( 0, G4ThreeVector(0., 0., -266*CLHEP::mm), lCollimator2, "Collimator2", lAlBox2, false, 0, checkOverlaps ); //------------------------------------------------------------------------------------ // 1st dose monitor // Position relative to box: z = -582/2 + 66 mm // - Refer to the wiki for more information // - Add 0.002 mm to z dimension of inner part to fix visualisation //------------------------------------------------------------------------------------ // Box containing dose monitor sDoseMonitor1 = new G4Box( "DoseMonitor1", 160.*CLHEP::mm/2, 160.*CLHEP::mm/2, 37.*CLHEP::mm/2 ); lDoseMonitor1 = new G4LogicalVolume( sDoseMonitor1, fAir, "DoseMonitor1" ); new G4PVPlacement( 0, G4ThreeVector(0., 0., -225.*CLHEP::mm), lDoseMonitor1, "DoseMonitor1", lAlBox2, false, 0, checkOverlaps ); lDoseMonitor1->SetVisAttributes( invisibleVisAtt ); // 1st perspex layer // Position in dose monitor: z = -37/2 + 12.59 mm + 5 um // - Thickness: 8 mm sMonitorPerspexBlock1 = new G4Box( "MonitorPerspexBlock1", 160.*CLHEP::mm/2, 160.*CLHEP::mm/2, 7.997*CLHEP::mm/2 ); sMonitorPerspexHole1 = new G4Tubs( "MonitorPerspexHole1", 0., 30.*CLHEP::mm, 8.*CLHEP::mm/2, startAngle, spanningAngle ); sMonitorPerspexLayer1 = new G4SubtractionSolid( "MonitorPerspexLayer1", sMonitorPerspexBlock1, sMonitorPerspexHole1 ); lMonitorPerspexLayer1 = new G4LogicalVolume( sMonitorPerspexLayer1, fPMMA, "MonitorPerspexLayer1" ); pMonitorPerspexLayer1 = new G4PVPlacement( 0, G4ThreeVector(0., 0., -5.905*CLHEP::mm), lMonitorPerspexLayer1, "MonitorPerspexLayer1", lDoseMonitor1, false, 0, checkOverlaps ); lMonitorPerspexLayer1->SetVisAttributes( perspexVisAtt ); // 1st mylar layer // Position in dose monitor: z = -37/2 + 16.59 mm + 7.5 um // - Thickness: 0.005 mm sMonitorMylar1 = new G4Box( "MonitorMylar1", 160.*CLHEP::mm/2, 160.*CLHEP::mm/2, 0.005*CLHEP::mm/2 ); lMonitorMylar1 = new G4LogicalVolume( sMonitorMylar1, fMylar, "MonitorMylar1" ); new G4PVPlacement( 0, G4ThreeVector(0., 0., -1.9025*CLHEP::mm), lMonitorMylar1, "MonitorMylar1", lDoseMonitor1, false, !checkOverlaps ); lMonitorMylar1->SetVisAttributes( mylarVisAtt ); // 1st aluminium layer // Position in dose monitor: z = -37/2 + 16.69 mm + 9.5 um // - Thickness: 0.001 mm sMonitorAl1 = new G4Box( "MonitorAl1", 160.*CLHEP::mm/2, 160.*CLHEP::mm/2, 0.001*CLHEP::mm/2 ); lMonitorAl1 = new G4LogicalVolume( sMonitorAl1, fAluminium, "MonitorAl1" ); new G4PVPlacement( 0, G4ThreeVector(0., 0., -1.8005*CLHEP::mm), lMonitorAl1, "MonitorAl1", lDoseMonitor1, false, !checkOverlaps ); lMonitorAl1->SetVisAttributes( perspexVisAtt ); // 2nd perspex layer // Position in dose monitor: z = -37/2 + 17.2 mm // - Thickness: 1 mm sMonitorPerspexBlock2 = new G4Box( "MonitorPerspexBlock2", 160.*CLHEP::mm/2, 160.*CLHEP::mm/2, 0.997*CLHEP::mm/2 ); sMonitorPerspexHole2 = new G4Tubs( "MonitorPerspexHole2", 0., 30.*CLHEP::mm, 1.*CLHEP::mm/2, startAngle, spanningAngle ); sMonitorPerspexLayer2 = new G4SubtractionSolid( "MonitorPerspexLayer2", sMonitorPerspexBlock2, sMonitorPerspexHole2 ); lMonitorPerspexLayer2 = new G4LogicalVolume( sMonitorPerspexLayer2, fPMMA, "MonitorPerspexLayer2" ); new G4PVPlacement( 0, G4ThreeVector(0., 0., -1.3*CLHEP::mm), lMonitorPerspexLayer2, "MonitorPerspexLayer2", lDoseMonitor1, false, 0, checkOverlaps ); lMonitorPerspexLayer2->SetVisAttributes( perspexVisAtt ); // Guard ring // Position in dose monitor: z = -37/2 mm // - Provides air gap for ionisation chamber sGuardRing = new G4Tubs( "GuardRing", 30.*CLHEP::mm, 50.*CLHEP::mm, 1.6*CLHEP::mm/2, startAngle, spanningAngle ); lGuardRing = new G4LogicalVolume( sGuardRing, fBrass, "GuardRing" ); new G4PVPlacement( 0, G4ThreeVector(0., 0., 0.), lGuardRing, "GuardRing", lDoseMonitor1, false, 0, checkOverlaps ); lGuardRing->SetVisAttributes( brassVisAtt ); // 3rd perspex layer // Position in dose monitor: z = -37/2 + 19.8 mm // - Replicates 2nd perspex layer in different position pMonitorPerspexLayer3 = new G4PVPlacement( 0, G4ThreeVector(0., 0., 1.3*CLHEP::mm), lMonitorPerspexLayer2, "MonitorPerspexLayer3", lDoseMonitor1, false, 0, checkOverlaps ); // 2nd aluminium layer // Position in dose monitor: z = -37/2 + 20.3 mm + 5 um // - Replicates 1st aluminium layer in different position pMonitorAl2 = new G4PVPlacement( 0, G4ThreeVector(0., 0., 1.8005*CLHEP::mm), lMonitorAl1, "MonitorAl2", lDoseMonitor1, false, 0, checkOverlaps ); // 2nd mylar layer // Position in dose monitor: z = -37/2 + 20.4 mm + 25 um // - Replicates 1st mylar layer in different position pMonitorMylar2 = new G4PVPlacement(0, G4ThreeVector(0, 0, 1.9025*CLHEP::mm), lMonitorMylar1, "MonitorMylar2", lDoseMonitor1, false, 0, checkOverlaps); // 4th perspex layer // Position in dose monitor: z = -37/2 + 24.4 mm + 5 um // - Replicates 1st perspex layer in different position pMonitorPerspexLayer4 = new G4PVPlacement(0, G4ThreeVector(0, 0, 5.905*CLHEP::mm), lMonitorPerspexLayer1, "MonitorPerspexLayer4", lDoseMonitor1, false, 0, checkOverlaps); //------------------------------------------------------------------------------------ // 2nd dose monitor // Position relative to box: z = -582/2 + 121.5 mm // - Replicates 1st dose monitor in different position //------------------------------------------------------------------------------------ pDoseMonitor2 = new G4PVPlacement( 0, G4ThreeVector(0., 0., -169.5*CLHEP::mm), lDoseMonitor1, "DoseMonitor2", lAlBox2, false, 0, checkOverlaps ); //------------------------------------------------------------------------------------ // Tungsten cross-wires // Position relative to box: z = -582/2 + 431 mm //------------------------------------------------------------------------------------ // Fixture holding wires sWiresFixtureOut = new G4Box( "WiresFixtureOut", 160.*CLHEP::mm/2, 160.*CLHEP::mm/2, 40.*CLHEP::mm/2 ); sWiresFixtureIn = new G4Box( "WiresFixtureIn" , 140.*CLHEP::mm/2, 140.*CLHEP::mm/2, 40.005*CLHEP::mm/2 ); sWiresFixture = new G4SubtractionSolid( "WiresFixture", sWiresFixtureOut, sWiresFixtureIn ); lWiresFixture = new G4LogicalVolume( sWiresFixture, fAluminium, "WiresFixture" ); pWiresFixture = new G4PVPlacement( 0, G4ThreeVector(0., 0., 140.*CLHEP::mm), lWiresFixture, "WiresFixture", lAlBox2, false, 0, checkOverlaps ); // Rotation for wire 1 in yz-plane (around x-axis) such that it aligns with the y-axis G4RotationMatrix xRot90deg = G4RotationMatrix(); xRot90deg.rotateX( M_PI/2*CLHEP::rad ); G4Transform3D rotWire1 = G4Transform3D( xRot90deg, G4ThreeVector(0., 0., 19.8*CLHEP::mm) ); // Rotation for wire 2 in xz-plane (around y-axis) such that it aligns with the x-axis G4RotationMatrix yRot90deg = G4RotationMatrix(); yRot90deg.rotateY( M_PI/2*CLHEP::rad ); G4Transform3D rotWire2 = G4Transform3D( yRot90deg, G4ThreeVector(0., 0., 19.8*CLHEP::mm) ); // First wire sCrossWire1 = new G4Tubs( "CrossWire1", 0., 0.4*CLHEP::mm/2, 140.*CLHEP::mm/2, startAngle, spanningAngle); lCrossWire1 = new G4LogicalVolume( sCrossWire1, fTungsten, "CrossWire1" ); pCrossWire1 = new G4PVPlacement( rotWire1, lCrossWire1, "CrossWire1", lWiresFixture, false, 0, !checkOverlaps ); lCrossWire1->SetVisAttributes( wiresVisAtt ); // Second wire // - Replicates first wire in different position and orientation pCrossWire2 = new G4PVPlacement( rotWire2, lCrossWire1, "CrossWire2", lWiresFixture, false, 0, !checkOverlaps ); //------------------------------------------------------------------------------------ // Disk to cover hole between nozzle and 2nd aluminium box // Position relative to room: z = -4200 (room) + 1396 (centre of box) // + 592/2 (length of box) + 5 (centre of cover) mm // - Required to avoid protons slipping through gaps and resulting in a halo // around the central beam //------------------------------------------------------------------------------------ G4VSolid* sCover = new G4Tubs( "Cover", 20.*CLHEP::mm, 30.*CLHEP::mm, 10.*CLHEP::mm/2, startAngle, spanningAngle ); G4LogicalVolume* lCover = new G4LogicalVolume( sCover, fBrass, "Cover" ); new G4PVPlacement( 0, G4ThreeVector(0., 0., -2503.*CLHEP::mm), lCover, "Cover", lRoomIn, false, 0, checkOverlaps ); //------------------------------------------------------------------------------------ // Nozzle // Position relative to room: z = -4200 + 1396 + 592/2 + 66.5/2 mm //------------------------------------------------------------------------------------ G4VSolid* sNozzleIn = new G4Tubs( "NozzleIn", 17*CLHEP::mm, 21*CLHEP::mm, 20.*CLHEP::mm/2, startAngle, spanningAngle ); G4LogicalVolume* lNozzleIn = new G4LogicalVolume( sNozzleIn, fBrass, "NozzleIn" ); new G4PVPlacement( 0, G4ThreeVector(0., 0., 286.*CLHEP::mm), lNozzleIn, "NozzleIn", lAlBox2, false, 0, !checkOverlaps ); sNozzle = new G4Tubs("Nozzle", 17*CLHEP::mm, 20*CLHEP::mm, 66.5*CLHEP::mm/2, startAngle, spanningAngle); lNozzle = new G4LogicalVolume(sNozzle, fBrass, "Nozzle"); pNozzle = new G4PVPlacement(0, G4ThreeVector(0, 0, -2474.75*CLHEP::mm), lNozzle, "Nozzle", lRoomIn, false, 0, checkOverlaps); //------------------------------------------------------------------------------------ // Collimator // Position relative to room: z = -4200 + 1396 + 592/2 + 66.5 mm // - Make sure the narrower part of the collimator sits inside the nozzle //------------------------------------------------------------------------------------ // Rotation matrix for offset in collimator orientation if needed G4RotationMatrix *collimatorOffset = new G4RotationMatrix(); G4double collimatorOffsetAngle = 0.*CLHEP::deg; collimatorOffset->rotateY( collimatorOffsetAngle/CLHEP::rad ); // Collimator disk // - The outer radius has been clipped by 0.002 mm to avoid coinciding edges in the geometry sCollimator3Disk = new G4Tubs( "Collimator3Disk", 0.99*CLHEP::mm, 19.998*CLHEP::mm, 8.*CLHEP::mm/2, startAngle, spanningAngle ); // Portion of ring cut out so the collimator fits partly inside the nozzle sCollimator3Cut = new G4Tubs( "Collimator3Cut", 17.*CLHEP::mm, 20.*CLHEP::mm, 4.*CLHEP::mm/2, startAngle, spanningAngle ); // Move sCollimator3Cut by 2 mm before subtracting to achieve desired geometry // - Shifted a further 0.005 mm to avoid overlapping edges sCollimator3 = new G4SubtractionSolid( "Collimator3", sCollimator3Disk, sCollimator3Cut, 0, G4ThreeVector(0., 0., -2.005*CLHEP::mm) ); lCollimator3 = new G4LogicalVolume( sCollimator3, fBrass, "Collimator3" ); pCollimator3 = new G4PVPlacement( collimatorOffset, G4ThreeVector(0., 0., -2441.5*CLHEP::mm), lCollimator3, "Collimator3", lRoomIn, false, !checkOverlaps ); //------------------------------------------------------------------------------------ // Cap holding collimator // Position relative to room: z = -4200 + 1396 + 592/2 + 66.5 // - 25/2 (half the cap) + 8/2 (half of collimator) mm //------------------------------------------------------------------------------------ sCapCylinder = new G4Tubs( "cap_cylinder", 20.*CLHEP::mm, 22.5*CLHEP::mm, 25.*CLHEP::mm/2, startAngle, spanningAngle ); sCapFront = new G4Tubs( "cap_front", 15.*CLHEP::mm, 22.5*CLHEP::mm, 5.*CLHEP::mm/2, startAngle, spanningAngle ); // Make sure sCapFront sits at the front of the cap // Shifted by half the cylinder length + half its own length sCap = new G4UnionSolid( "Cap", sCapCylinder, sCapFront, 0, G4ThreeVector(0., 0., 15.*CLHEP::mm) ); lCap = new G4LogicalVolume( sCap, fBrass, "Cap" ); pCap = new G4PVPlacement( 0, G4ThreeVector(0., 0., -2450.*CLHEP::mm), lCap, "Cap", lRoomIn, false, 0, checkOverlaps ); //------------------------------------------------------------------------------------ // Shielding // - Shields from neutrons on either side of the beamline // - Reaches from end of first tube to half-way down second aluminium box //------------------------------------------------------------------------------------ // First shield // Position relative to room: x = 110 + 37/2 mm // y = 15 mm // z = -4200 + 356 + 1140/2 mm sShielding1 = new G4Box( "Shielding1", 37.*CLHEP::mm/2, 230.*CLHEP::mm/2, 1140.*CLHEP::mm/2 ); lShielding1 = new G4LogicalVolume( sShielding1, fBoratedPlastic, "Shielding1" ); pShielding1 = new G4PVPlacement( 0, G4ThreeVector(128.5*CLHEP::mm, 15.*CLHEP::mm, -3374.*CLHEP::mm), lShielding1, "Shielding1", lRoomIn, false, 0, checkOverlaps ); lShielding1->SetVisAttributes( invisibleVisAtt ); // Second shield // Position relative to room: x = -110 - 37/2 mm // y = 15 mm // z = -4200 + 356 + 1140/2 mm // - Replicates first shield in different position pShielding2 = new G4PVPlacement( 0, G4ThreeVector(-128.5*CLHEP::mm, 15.*CLHEP::mm, -3374.*CLHEP::mm), lShielding1, "Shielding2", lRoomIn, false, 0, checkOverlaps ); //------------------------------------------------------------------------------------ // Detector // Position set in macro through DetectorMessenger // - Padded volume to allow for wrapping around absorber etc. //------------------------------------------------------------------------------------ sDetector = new G4Box( "Detector", detSizeXY/2, detSizeXY/2, detSizeZ/2 ); lDetector = new G4LogicalVolume( sDetector, fWorldMaterial, "Detector" ); pDetector = new G4PVPlacement( 0, fDetPosition, lDetector, "Detector", lRoomIn, false, 0, checkOverlaps ); lDetector->SetVisAttributes( invisibleVisAtt ); // Absorber // Placed in centre of detector volume sAbsor = new G4Box( "Absorber", fAbsorSizeXY/2, fAbsorSizeXY/2, fAbsorSizeZ/2 ); lAbsor = new G4LogicalVolume( sAbsor, fAbsorMaterial, "Absorber" ); pAbsor = new G4PVPlacement( 0, G4ThreeVector(0., 0., 0.), lAbsor, "Absorber", lDetector, false, 0, checkOverlaps ); lAbsor->SetVisAttributes( invisibleVisAtt ); // Layers in absorber for segmented detector if (fLayerNumber > 0) { // fLayerNumber set in macro fLayerSizeZ = fAbsorSizeZ/fLayerNumber; G4Box* sLayer = new G4Box( "Layer", fLayerSizeXY/2, fLayerSizeXY/2, fLayerSizeZ/2 ); lLayer = new G4LogicalVolume( sLayer, fAbsorMaterial, "Layer" ); pLayer = new G4PVReplica( "Layer", lLayer, lAbsor, kZAxis, fLayerNumber, fLayerSizeZ ); G4double layerVolume = fLayerSizeXY*fLayerSizeXY*fLayerSizeZ; G4double layerDensity = fAbsorMaterial->GetDensity(); fLayerMass = layerVolume*layerDensity; } PrintParameters(); // Always return the World volume return pWorld; } void DetectorConstruction::PrintParameters() { // Print parameters when the detector is constructed G4cout << *( G4Material::GetMaterialTable() ) << G4endl; G4cout << "\n---------------------------------------------------------\n"; G4cout << "---> The Absorber is " << G4BestUnit(fAbsorSizeZ,"Length") << " of " << fAbsorMaterial->GetName() << G4endl; G4cout << "\n---------------------------------------------------------\n"; } void DetectorConstruction::SetMaterial( G4String materialChoice ) { // Used by DetectorMessenger to set absorber material to that chosen in macro G4Material* material = G4NistManager::Instance()->FindOrBuildMaterial( materialChoice ); if ( material ) { fAbsorMaterial = material; if ( lAbsor ) { lAbsor->SetMaterial( fAbsorMaterial ); lLayer->SetMaterial( fAbsorMaterial ); G4RunManager::GetRunManager()->PhysicsHasBeenModified(); } } } void DetectorConstruction::SetSizeZ( G4double value ) { fAbsorSizeZ = value; G4RunManager::GetRunManager()->GeometryHasBeenModified(); } void DetectorConstruction::SetSizeXY( G4double value ) { fAbsorSizeXY = value; G4RunManager::GetRunManager()->GeometryHasBeenModified(); } void DetectorConstruction::SetLayerSizeXY( G4double value ) { fLayerSizeXY = value; G4RunManager::GetRunManager()->GeometryHasBeenModified(); } void DetectorConstruction::SetLayerNumber( G4int value ) { fLayerNumber = value; G4RunManager::GetRunManager()->GeometryHasBeenModified(); } void DetectorConstruction::UpdateGeometry() { G4RunManager::GetRunManager()->PhysicsHasBeenModified(); G4RunManager::GetRunManager()->DefineWorldVolume( ConstructVolumes() ); }