using Geant4
using Geant4.SystemOfUnits
using Parameters
#---Detector parameters----------------------------------------------------------------------------
# The TES array of the X-IFU: 317 square Bi absorbers on a Si3N4 membrane and a Si grid, inside a
# hexagonal envelope. Only the parameters of the array are exposed. The dimensions of the supports,
# shields and cryostat come from a CAD model and are fixed in the construction function.
@with_kw mutable struct XrayTESDetector <: G4JLDetector
absorberThickness::Float64 = 3μm ## Bi absorber
membraneThickness::Float64 = 0.75μm ## Si3N4 membrane under the absorbers
gridThickness::Float64 = 200μm ## Si grid supporting the membrane
gridBeam::Float64 = 165μm ## width of the grid walls
waferThickness::Float64 = 0.25mm ## Si support wafer around the array
pixelPitch::Float64 = 0.814mm
pixelGap::Float64 = 11μm
arrayApothem::Float64 = 8.5mm ## apothem of the hexagonal envelope of the array
pixelApothem::Float64 = 8.4mm ## pixels must fit inside this hexagon
checkOverlaps::Bool = false
##---filled by the construction
arrayPV::CxxPtr{G4VPhysicalVolume} = CxxPtr{G4VPhysicalVolume}(C_NULL)
absorberPV::CxxPtr{G4VPhysicalVolume} = CxxPtr{G4VPhysicalVolume}(C_NULL)
acdLVs::Vector{CxxPtr{G4LogicalVolume}} = CxxPtr{G4LogicalVolume}[]
end
# Positions of the pixels: the cells of a square lattice that fit inside a hexagon with flat sides
# at the top and bottom (as the G4Polyhedra envelope), numbered row by row from the bottom.
function pixelPositions(det::XrayTESDetector)
(; pixelPitch, pixelApothem) = det
inside(x, y) = abs(y) <= pixelApothem && abs(x) * √3/2 + abs(y)/2 <= pixelApothem
n = ceil(Int, pixelApothem / pixelPitch) + 1
positions = Tuple{Float64,Float64}[]
for j in -n:n, i in -n:n
x, y = i * pixelPitch, j * pixelPitch
all(inside(x + dx * pixelPitch/2, y + dy * pixelPitch/2) for dx in (-1, 1), dy in (-1, 1)) && push!(positions, (x, y))
end
return positions
end
# Name of the region of the volumes near the detector
const innerRegion = "InnerRegion"
# Visualization attributes (colour and transparency) of a logical volume
setVis(lv, r, g, b, a=1.; visible=true) = SetVisAttributes(lv, G4VisAttributes(visible, G4Colour(r, g, b, a)))
# Hexagonal prism (6 sides) between z = -hz and z = hz, with inner and outer apothems at both ends.
# The arrays are passed to C++ as pointers, so they must be kept alive during the call.
function hexagon(name, hz, rin, rout)
z, ri, ro = [-hz, hz], collect(Float64, rin), collect(Float64, rout)
GC.@preserve z ri ro G4Polyhedra(name, 0, 2π, 6, 2, z, ri, ro)
end
function rotation(; x=0, y=0, z=0)
rot = G4RotationMatrix()
x != 0 && rotateX(rot, x)
y != 0 && rotateY(rot, y)
z != 0 && rotateZ(rot, z)
return rot
end
#---Detector construction--------------------------------------------------------------------------
function xrayTESConstruct(det::XrayTESDetector)::CxxPtr{G4VPhysicalVolume}
(; absorberThickness, membraneThickness, gridThickness, gridBeam, waferThickness,
pixelPitch, pixelGap, arrayApothem, checkOverlaps) = det
nist = G4NistManager!Instance()
#---Materials----------------------------------------------------------------------------------
vacuum = FindOrBuildMaterial(nist, "G4_Galactic")
Si = FindOrBuildMaterial(nist, "G4_Si")
Cu = FindOrBuildMaterial(nist, "G4_Cu")
Bi = FindOrBuildMaterial(nist, "G4_Bi")
Al = FindOrBuildMaterial(nist, "G4_Al")
Au = FindOrBuildMaterial(nist, "G4_Au")
Ti = FindOrBuildMaterial(nist, "G4_Ti")
if G4Material!GetMaterial("Cryoperm", false) == C_NULL
ringAl = G4Material("RingAl", density=0.736g/cm3, ncomponents=1) ## Al with the average density of the ring
AddMaterial(ringAl, Al, 1.)
cryoperm = G4Material("Cryoperm", density=8.7g/cm3, ncomponents=4)
for (el, f) in (("G4_Ni", 0.775), ("G4_Cu", 0.045), ("G4_Mo", 0.025), ("G4_Fe", 0.155))
AddMaterial(cryoperm, FindOrBuildMaterial(nist, el), f)
end
steel = G4Material("StainlessSteel", density=8.03g/cm3, ncomponents=8)
for (el, f) in (("G4_N", 0.01), ("G4_Ni", 0.1), ("G4_Cr", 0.185), ("G4_S", 0.03),
("G4_P", 0.045), ("G4_Mn", 0.02), ("G4_C", 0.08), ("G4_Fe", 0.53))
AddMaterial(steel, FindOrBuildMaterial(nist, el), f)
end
si3n4 = G4Material("Si3N4", density=3.44g/cm3, ncomponents=2)
AddElement(si3n4, FindOrBuildElement(nist, "Si"), Int32(3))
AddElement(si3n4, FindOrBuildElement(nist, "N"), Int32(4))
end
ringAl = G4Material!GetMaterial("RingAl")
cryoperm = G4Material!GetMaterial("Cryoperm")
steel = G4Material!GetMaterial("StainlessSteel")
si3n4 = G4Material!GetMaterial("Si3N4")
#---World--------------------------------------------------------------------------------------
worldLV = G4LogicalVolume(G4Box("World", 3m, 3m, 3m), vacuum, "World")
worldPV = G4PVPlacement(nothing, G4ThreeVector(), worldLV, "World", nothing, false, 0, checkOverlaps)
setVis(worldLV, 1, 1, 1, visible=false)
# Logical volume with a colour, and placements in the world
function volume(solid, material, name, color...; visible=true)
lv = G4LogicalVolume(solid, material, name)
setVis(lv, color..., visible=visible)
return lv
end
place(lv, name, x, y, z; copy=0) = G4PVPlacement(nothing, G4ThreeVector(x, y, z), lv, name, worldLV, false, copy, checkOverlaps)
place(lv, name, rot::G4RotationMatrix, x, y, z) = G4PVPlacement(G4Transform3D(rot, G4ThreeVector(x, y, z)), lv, name, worldLV, false, 0, checkOverlaps)
#---TES array----------------------------------------------------------------------------------
# Each pixel element (a box of one pitch) contains the Bi absorber, the Si3N4 membrane and a piece
# of the Si grid.
elementZ = absorberThickness + gridThickness + membraneThickness
pixelSize = pixelPitch - pixelGap
detectorLV = volume(hexagon("Detector", elementZ/2, (0, 0), (arrayApothem, arrayApothem)), vacuum, "Detector", 1, 1, 1, visible=false)
det.arrayPV = G4PVPlacement(nothing, G4ThreeVector(0, 0, -elementZ + 0.0001μm), detectorLV, "Detector", worldLV, false, 0, checkOverlaps)
elementLV = volume(G4Box("Element", pixelPitch/2, pixelPitch/2, elementZ/2), vacuum, "Element", 1, 1, 1, visible=false)
absorberLV = volume(G4Box("Bipxl", pixelSize/2, pixelSize/2, absorberThickness/2), Bi, "Bipxl", 1.0, 0.8, 0.0)
det.absorberPV = G4PVPlacement(nothing, G4ThreeVector(0, 0, elementZ/2 - absorberThickness/2), absorberLV, "Bipxl", elementLV, false, 0, checkOverlaps)
membraneLV = volume(G4Box("Membrane", pixelSize/2, pixelSize/2, membraneThickness/2), si3n4, "Membrane", 0.5, 0.5, 0.9)
G4PVPlacement(nothing, G4ThreeVector(0, 0, elementZ/2 - absorberThickness - membraneThickness/2), membraneLV, "Membrane", elementLV, false, 0, checkOverlaps)
gridBox = G4Box("GridBox", pixelPitch/2, pixelPitch/2, gridThickness/2)
gridHole = G4Box("GridHole", (pixelPitch - gridBeam)/2, (pixelPitch - gridBeam)/2, gridThickness/2 + 0.5mm)
gridLV = volume(G4SubtractionSolid("GridPiece", move!(gridBox), move!(gridHole)), Si, "GridPiece", 0.6, 0.6, 0.6)
G4PVPlacement(nothing, G4ThreeVector(0, 0, elementZ/2 - absorberThickness - membraneThickness - gridThickness/2), gridLV, "GridPiece", elementLV, false, 0, checkOverlaps)
# The 317 pixels are a parameterised volume. The Julia function `pixelTransform` gives the
# position of each copy, and the copy number is the pixel number.
positions = pixelPositions(det)
pixelTransform(copyNo, pv, positions) = (SetTranslation(pv, G4ThreeVector(positions[copyNo+1]..., 0)); nothing)
G4PVParameterised("Element", elementLV, detectorLV, kXAxis, length(positions), pixelTransform;
data=positions, checkOverlaps=checkOverlaps)
#---Support wafer around the array-------------------------------------------------------------
waferZ = -elementZ/2 - absorberThickness - gridThickness/2
waferLV = volume(hexagon("Wafer", waferThickness/2, (arrayApothem, arrayApothem), (39.4mm, 19.7mm)), Si, "Wafer", 0.4, 0.4, 0.5)
place(waferLV, "Wafer", 0, 0, waferZ)
#---Backscattering (BSC) surface: an empty volume just above the absorbers---------------------
bscHZ = 0.05mm
bscLV = volume(hexagon("BSC", bscHZ, (0, 0), (arrayApothem + 2mm, arrayApothem + 2mm)), vacuum, "BSC", 1, 1, 1, visible=false)
place(bscLV, "BSC", 0, 0, waferZ + waferThickness + bscHZ/2)
#---Anti-coincidence detector (ACD): 4 Si trapezoids under the array, each with an inner part----
acdThickness, acdGap = 200μm, 50μm
acdZ = -(0.75mm + absorberThickness/2 + acdThickness/2)
height = 8.5mm
wide = height * 1.191 ## sides of the trapezoids (the CAD values)
narrow = wide/2
# The inner part could have higher production cuts to reduce the number of secondaries
innerACD = G4Trap("InnerACD", acdThickness - 50μm, height - 50μm, wide - 50μm, (wide - 50μm)/2)
outerACD = G4SubtractionSolid("ACD", move!(G4Trap("ACDBox", acdThickness, height, wide, narrow)), CxxPtr(innerACD))
innerLV = volume(innerACD, Si, "InnerACD", 0.2, 0.7, 0.2)
acdLV = volume(outerACD, Si, "ACD", 0.2, 0.8, 0.2)
det.acdLVs = [CxxPtr(innerLV), CxxPtr(acdLV)]
ax, ay = (narrow * 1.5 + acdGap)/2, (height + acdGap)/2
for (k, (sx, sy, rot)) in enumerate(((1, 1, (;)), (-1, -1, (z=π,)), (1, -1, (x=π,)), (-1, 1, (y=π,))))
place(innerLV, "ACDInner$k", rotation(; rot...), sx * ax, sy * ay, acdZ)
place(acdLV, "ACD$k", rotation(; rot...), sx * ax, sy * ay, acdZ)
end
#---ACD support plate--------------------------------------------------------------------------
plateLV = volume(hexagon("ACDPlate", 1.75mm, (wide, wide), (43mm, 43mm)), Cu, "ACDPlate", 0.9, 0.5, 0.2)
place(plateLV, "ACDPlate", 0, 0, -2.25mm)
#---Cage: columns and walls of Cu supporting the detector (simplified from a CAD model)--------
cageZ = -36.5027mm
columnLV = volume(G4Tubs("CageColumn", 0, 3.99mm, 30mm, 0, 2π), Cu, "CageColumn", 0.9, 0.5, 0.2)
for (k, (x, y)) in enumerate(((45.75, 0), (-45.75, 0), (22.875, 39.621), (22.875, -39.621), (-22.875, -39.621), (-22.875, 39.621)))
place(columnLV, "CageColumn$k", x*mm, y*mm, cageZ)
end
hollowLV = volume(G4Tubs("HollowCageColumn", 1.25mm, 3mm, 30mm, 0, 2π), Cu, "HollowCageColumn", 0.9, 0.5, 0.2)
for (k, (x, y)) in enumerate(((22.875, 0), (-11.4375, -19.8103311), (-11.4375, 19.810331)))
place(hollowLV, "HollowCageColumn$k", x*mm, y*mm, cageZ)
end
wallLV = volume(G4Box("CageWall", 0.5mm, 16.31mm, 32.5mm), Cu, "CageWall", 0.9, 0.5, 0.2)
place(wallLV, "CageWall1", 22.875mm, 19.3103311mm, cageZ)
place(wallLV, "CageWall2", 22.875mm, -19.3103311mm, cageZ)
place(wallLV, "CageWall3", rotation(z=-60deg), 5.2857373mm, 29.4654967mm, cageZ)
place(wallLV, "CageWall4", rotation(z=-60deg), -28.1607373mm, 10.1551656mm, cageZ)
place(wallLV, "CageWall5", rotation(z=60deg), -28.1607373mm, -10.1551656mm, cageZ)
place(wallLV, "CageWall6", rotation(z=60deg), 5.2857373mm, -29.4654967mm, cageZ)
miniLV = volume(G4Box("MiniCageWall", 7.9375mm, 0.5mm, 32.5mm), Cu, "MiniCageWall", 0.9, 0.5, 0.2)
place(miniLV, "MiniCageWall1", 33.8125mm, 0, cageZ)
place(miniLV, "MiniCageWall2", rotation(z=-60deg), -16.90625mm, 29.282484mm, cageZ)
place(miniLV, "MiniCageWall3", rotation(z=-120deg), -16.90625mm, -29.282484mm, cageZ)
extLV = volume(G4Box("ExtCageWall", 0.925mm, 18.875mm, 32.5mm), Cu, "ExtCageWall", 0.9, 0.5, 0.2)
place(extLV, "ExtCageWall1", rotation(z=-30deg), -35.0724512mm, 20.2490891mm, cageZ)
place(extLV, "ExtCageWall2", rotation(z=-30deg), 35.0724512mm, -20.2490891mm, cageZ)
boardLV = volume(G4Box("ExtBoard", 0.25mm, 18.25mm, 32.25mm), Si, "ExtBoard", 0.2, 0.5, 0.2)
place(boardLV, "ExtBoard1", rotation(z=-30deg), 37.932mm, -21.9mm, -36.253mm)
place(boardLV, "ExtBoard2", rotation(z=-30deg), -37.932mm, 21.9mm, -36.253mm)
#---First thermal shield (Cryoperm)------------------------------------------------------------
for (name, rmin, rmax, hz, z) in (("FirstShieldBottom", 0, 80mm, 0.5mm, -101mm),
("FirstShieldSide", 79mm, 80mm, 72.5mm, -28mm),
("FirstShieldTop", 31.85mm, 80mm, 0.5mm, 45mm),
("FirstShieldTopCyl", 31.85mm, 32.85mm, 37mm, 82.5mm))
place(volume(G4Tubs(name, rmin, rmax, hz, 0, 2π), cryoperm, name, 0.5, 0.5, 0.7, 0.3), name, 0, 0, z)
end
#---Ring: simplified as a tube with 3 flat cuts, made of Al with the average density----------
ring = G4Tubs("RingTube", 80mm, 97.1mm, 42.5mm, 0, 2π)
cut = G4Box("RingCut", 38.781347139mm/2, 116.620103593mm/2, 85.1mm/2)
ring1 = G4SubtractionSolid("Ring1", move!(ring), CxxPtr(cut), CxxPtr{G4RotationMatrix}(C_NULL), G4ThreeVector(-105.055643631mm, 0, 0))
ring2 = G4SubtractionSolid("Ring2", move!(ring1), CxxPtr(cut), move!(rotation(z=60deg)), G4ThreeVector(52.527821885mm, -90.980856208mm, 0))
ring3 = G4SubtractionSolid("Ring", move!(ring2), move!(cut), move!(rotation(z=120deg)), G4ThreeVector(52.527821885mm, 90.980856208mm, 0))
place(volume(ring3, ringAl, "Ring", 0.7, 0.7, 0.7, 0.3), "Ring", 0, 0, -22mm)
#---Second thermal shield (Al): extruded hexagonal shape with bottom and top plates------------
toPolygon(points) = (v = StdVector{CLHEP!Hep2Vector}(); for (x, y) in points push!(v, CLHEP!Hep2Vector(x*mm, y*mm)) end; v)
outline = toPolygon(((58.936, 154.115), (104, 128.098), (104, -128.098), (58.936, -154.115), (-162.936, -26.018), (-162.936, 26.018)))
inline = toPolygon(((58.936, 149.762), (100.23, 125.921), (100.23, -125.921), (58.936, -149.762), (-159.166, -23.841), (-159.166, 23.841)))
bottom = G4SubtractionSolid("SecondShieldBottom", move!(G4ExtrudedSolid("SSBottom", outline, 1.325mm)), move!(G4Tubs("SSHole", 0, 19mm, 1.5mm, 0, 2π)))
place(volume(bottom, Al, "SecondShieldBottom", 0.6, 0.6, 0.8, 0.3), "SecondShieldBottom", 0, 0, -110.178mm)
side = G4SubtractionSolid("SecondShieldSide", move!(G4ExtrudedSolid("SSOuter", outline, 107.675mm)), move!(G4ExtrudedSolid("SSInner", inline, 108mm)))
place(volume(side, Al, "SecondShieldSide", 0.6, 0.6, 0.8, 0.3), "SecondShieldSide", 0, 0, -1.178mm)
top = G4SubtractionSolid("SecondShieldTop", move!(G4ExtrudedSolid("SSTop", outline, 5.435mm)), move!(G4Tubs("SSHole2", 0, 36.85mm, 5.5mm, 0, 2π)))
place(volume(top, Al, "SecondShieldTop", 0.6, 0.6, 0.8, 0.3), "SecondShieldTop", 0, 0, 111.932mm)
place(volume(G4Tubs("SecondShieldTopCyl", 36.85mm, 39mm, 6mm, 0, 2π), Al, "SecondShieldTopCyl", 0.6, 0.6, 0.8, 0.3), "SecondShieldTopCyl", 0, 0, 123.367mm)
#---Third thermal shield (Al): a cylinder closed by two cones and a bottom plate---------------
sideH, coneH, t = 280mm, 40mm, 0.4mm
place(volume(G4Tubs("ThirdShieldSide", 174.6mm, 174.6mm + t, sideH/2, 0, 2π), Al, "ThirdShieldSide", 0.5, 0.7, 0.9, 0.2), "ThirdShieldSide", 0, 0, 0)
place(volume(G4Cons("ThirdShieldTopCone", 174.6mm, 174.6mm + t, 93mm, 93mm + t, coneH/2, 0, 2π), Al, "ThirdShieldTopCone", 0.5, 0.7, 0.9, 0.2),
"ThirdShieldTopCone", 0, 0, (sideH + coneH)/2)
place(volume(G4Cons("ThirdShieldBottomCone", 80mm, 80mm + t, 174.6mm, 174.6mm + t, coneH/2, 0, 2π), Al, "ThirdShieldBottomCone", 0.5, 0.7, 0.9, 0.2),
"ThirdShieldBottomCone", 0, 0, -(sideH + coneH)/2)
place(volume(G4Tubs("ThirdShieldBottom", 0, 80mm + t, t/2, 0, 2π), Al, "ThirdShieldBottom", 0.5, 0.7, 0.9, 0.2),
"ThirdShieldBottom", 0, 0, -(sideH + t)/2 - coneH)
#---External layer of the cryostat (Al)--------------------------------------------------------
r, midT, midH, sideT, sideH2, coneH2 = 200mm, 8.8mm, 120mm, 6.5mm, 85mm, 75mm
topConeR, botConeR = 97mm, 120mm
cryoColor = (0.6, 0.6, 0.6, 0.15)
place(volume(G4Tubs("CryostatMid", r, r + midT, midH/2, 0, 2π), Al, "CryostatMid", cryoColor...), "CryostatMid", 0, 0, 0)
place(volume(G4Tubs("CryostatTop", r, r + sideT, sideH2/2, 0, 2π), Al, "CryostatTop", cryoColor...), "CryostatTop", 0, 0, (midH + sideH2)/2)
place(volume(G4Cons("CryostatTopCone", r, r + sideT, topConeR, topConeR + sideT, coneH2/2, 0, 2π), Al, "CryostatTopCone", cryoColor...),
"CryostatTopCone", 0, 0, midH/2 + sideH2 + coneH2/2)
place(volume(G4Tubs("CryostatBottom", r, r + sideT, sideH2/2, 0, 2π), Al, "CryostatBottom", cryoColor...), "CryostatBottom", 0, 0, -(midH + sideH2)/2)
place(volume(G4Cons("CryostatBottomCone", botConeR, botConeR + sideT, r, r + sideT, coneH2/2, 0, 2π), Al, "CryostatBottomCone", cryoColor...),
"CryostatBottomCone", 0, 0, -midH/2 - sideH2 - coneH2/2)
place(volume(G4Tubs("CryostatBottomPlate", 0, botConeR, midT/2, 0, 2π), Al, "CryostatBottomPlate", cryoColor...),
"CryostatBottomPlate", 0, 0, -midH/2 - sideH2 - coneH2 + midT/2)
#---Radiation filter: 20 nm of Al on a stainless steel mesh, in an Al carrier------------------
filterHZ, meshT, carrierT, filterR, filterZ = 10nm, 80μm, 5mm, 64mm, 180mm
filterLV = volume(G4Tubs("AlFilter", 0, filterR, filterHZ, 0, 2π), Al, "AlFilter", 0.8, 0.8, 0.9, 0.5)
place(filterLV, "AlFilter", 0, 0, filterZ)
meshZ = filterZ - filterHZ - meshT/2
meshLV = volume(G4Tubs("Mesh", 0, filterR + 3.3mm, meshT/2, 0, 2π), vacuum, "Mesh", 1, 1, 1, visible=false)
place(meshLV, "Mesh", 0, 0, meshZ)
# Each cell of the mesh is a square frame made of 4 trapezoids
hx1, hx3, hy, dz = 4827/2*μm, 4880/2*μm, 80/2*μm, 26.5/2*μm
trapLV = volume(G4Trap("MeshBar", dz, 0, 0, hy, hx1, hx1, 0, hy, hx3, hx3, 0), steel, "MeshBar", 0.3, 0.3, 0.3)
trapRots = ((x=90deg,), (x=90deg, y=-90deg), (x=270deg,), (x=90deg, y=90deg))
trapPos = ((0, 1), (1, 0), (0, -1), (-1, 0))
for i in -13:13, j in -13:13
cx, cy = 2i * hx3, 2j * hx3
hypot(cx, cy) < filterR || continue
for (rot, (sx, sy)) in zip(trapRots, trapPos)
G4PVPlacement(rotation(; rot...), G4ThreeVector(cx + sx * (hx1 + dz), cy + sy * (hx1 + dz), 0), trapLV, "MeshBar", meshLV, false, 0, checkOverlaps)
end
end
place(volume(G4Tubs("FilterCarrier", filterR, filterR + 3.85mm, carrierT/2, 0, 2π), Al, "FilterCarrier", 0.6, 0.6, 0.6),
"FilterCarrier", 0, 0, meshZ + meshT/2 + carrierT/2)
#---Aperture cylinder (Ti, 300 K) with an inner Au coating--------------------------------------
acTop = midH/2 + sideH2 + coneH2
acH = acTop - filterZ - carrierT
acR1, acT = 67.8644mm, 1mm
place(volume(G4Cons("AC", acR1 - acT, acR1, topConeR - acT, topConeR, acH/2, 0, 2π), Ti, "AC", 0.7, 0.7, 0.8, 0.3), "AC", 0, 0, acTop - acH/2)
coatingLV = volume(G4Cons("ACCoating", acR1 - acT - 5μm, acR1 - acT, topConeR - acT - 5μm, topConeR - acT, acH/2, 0, 2π), Au, "ACCoating", 1.0, 0.85, 0.0, 0.3)
place(coatingLV, "ACCoating", 0, 0, acTop - acH/2)
#---The spacecraft: a 1 cm thick Al sphere------------------------------------------------------
place(volume(G4Sphere("Spacecraft", 26cm, 27cm, 0, 2π, 0, π), Al, "Spacecraft", 0.8, 0.8, 0.8, 0.1), "Spacecraft", 0, 0, 0)
#---Inner region: the volumes seen by the detector-----------------------------------------------
# The physics list can use more precise models in this region (single scattering, atomic
# deexcitation). The production cuts are the same as in the rest of the geometry.
region = G4Region(innerRegion)
for lv in (elementLV, detectorLV, absorberLV, membraneLV, gridLV, waferLV, acdLV, filterLV, coatingLV)
AddRootLogicalVolume(region, lv)
end
cuts = G4ProductionCuts()
SetProductionCut(cuts, 1mm)
SetProductionCuts(region, cuts)
SetEnergyRange(G4ProductionCutsTable!GetProductionCutsTable(), 200eV, 1000GeV)
return worldPV
end
Geant4.getConstructor(::XrayTESDetector)::Function = xrayTESConstruct