HBC30Detector.jl


mutable struct HBC30 <: G4JLDetector
    # main input parameters
    const chamberDiameter::Float64  # chamber diameter
    const targetLength::Float64     # length of target
    const checkOverlaps::Bool       # do check overlaps when creating the geometry
    # mutable data
    worldZHalfLength::Float64
    # constructor with defaults values for parameters
    function HBC30(; chamberDiameter=30cm,
                     targetLength=5cm,
                     checkOverlaps=false)
        self = new(chamberDiameter, targetLength, checkOverlaps)
        # derived parameters
        self.worldZHalfLength = 1.1 * (targetLength + chamberDiameter)/2
        return self
    end
end

import Geant4.SystemOfUnits:mole,cm3

function HBC30Construct(det::HBC30)::CxxPtr{G4VPhysicalVolume}
    (; chamberDiameter, targetLength, checkOverlaps) = det

    #---Materials----------------------------------------------------------------------------------
    G4Material("LH₂",  z=1., a=1.008*g/mole, density= 70.8*mg/cm3)
    nist = G4NistManager!Instance()
    m_air    = FindOrBuildMaterial(nist, "G4_AIR")
    m_lh2    = FindOrBuildMaterial(nist, "LH₂")
    m_glass  = FindOrBuildMaterial(nist, "G4_GLASS_PLATE")
    m_target = FindOrBuildMaterial(nist, "G4_W")
    m_lAr    = FindOrBuildMaterial(nist, "G4_lAr")

    #---Volumes------------------------------------------------------------------------------------
    worldS  = G4Box("world", det.worldZHalfLength, det.worldZHalfLength, det.worldZHalfLength)
    worldLV = G4LogicalVolume(worldS, m_air, "World")
    worldPV = G4PVPlacement(nothing, G4ThreeVector(), worldLV, "World", nothing, false, 0, checkOverlaps)

    chamberS  = G4Tubs("chamber", 0, chamberDiameter/2, 7.5cm, 0, 2π)
    chamberLV = G4LogicalVolume(chamberS, m_lh2, "chamber")
    G4PVPlacement(nothing, G4ThreeVector(), chamberLV, "chamber", worldLV, false, 0, checkOverlaps)
    SetUserLimits(chamberLV, G4UserLimits(5mm))

    windowS  = G4Tubs("window", 0, chamberDiameter/2, 1.5cm, 0, 2π)
    windowLV = G4LogicalVolume(windowS, m_glass, "window")
    G4PVPlacement(nothing, G4ThreeVector(0, 0, 7.5cm+1.5cm), windowLV, "window1", worldLV, false, 0, checkOverlaps)
    G4PVPlacement(nothing, G4ThreeVector(0, 0, -7.5cm-1.5cm), windowLV, "window2", worldLV, false, 0, checkOverlaps)

    targetS = G4Tubs("target", 0, 1cm, targetLength/2, 0, 2π)
    targetLV = G4LogicalVolume(targetS, m_air, "target")
    rot = G4RotationMatrix()
    rotateX(rot, π/2)
    trans = G4Transform3D(rot,G4ThreeVector(0, chamberDiameter/2+targetLength/2, 0))
    G4PVPlacement(trans, targetLV, "target", worldLV, false, 0, checkOverlaps)

    # Visualization attributes
    boxVisAtt = G4VisAttributes(G4Colour(1.0, 1.0, 1.0, 0.0))
    targetVisAtt = G4VisAttributes(G4Colour(1.0, 1.0, 1.0, 0.9))
    chamberVisAtt = G4VisAttributes(G4Colour(1.0, 1.0, 0.0, 0.1))
    windowVisAtt = G4VisAttributes(G4Colour(0.0, 0.0, 1.0, 0.05))
    SetVisAttributes(worldLV, boxVisAtt)
    SetVisAttributes(targetLV, targetVisAtt)
    SetVisAttributes(chamberLV, chamberVisAtt)
    SetVisAttributes(windowLV, windowVisAtt)

    # Always return the physical world-------------------------------------------------------------
    return worldPV
end

Geant4.getConstructor(::HBC30)::Function = HBC30Construct