Generating Fluence Maps
In order to compute dose, an idealised fluence distribution needs to be created.
This is usually done by generating fluence maps on a set of bixels from beam-limiting devices, such as the jaws or MLC.
Beam-Limiting Devices
Beam-limiting devices contain information on the position and shape of the aperture. These typically relate to physical devices on the treatment machine, such as a Multi-Leaf Collimator. Each have specialised methods by which they interact with bixels and assign an amount of fluence going through the bixel.
Jaws
Jaws are rectangular field shapes, which are simply constructed by specifying the position of the left, right, top and bottom jaws, or a fieldsize:
julia> jaws = Jaws(-10., 10., -15., 15.)
Jaws{Float64}([-10.0, 10.0], [-15.0, 15.0])
julia> jaws = Jaws(100.)
Jaws{Float64}([-50.0, 50.0], [-50.0, 50.0])
They have methods for accessing the positions, and the area,
julia> getx(jaws)
2-element StaticArraysCore.SVector{2, Float64} with indices SOneTo(2): -50.0 50.0
julia> gety(jaws)
2-element StaticArraysCore.SVector{2, Float64} with indices SOneTo(2): -50.0 50.0
julia> getarea(jaws)
10000.0
Multi-Leaf Collimator
Multi-Leac Collimator (MLC) contain the position of the leaves (in the x direction), and the position of the leaf edges (the y direction).
They are constructed by specifying leaf positions in a 2xn
matrix and leaf edges in an n+1
length vector,
julia> mlcx = [-10. -12. -23. 10. 4. -10.];
julia> mlcy = -5.:5.:10;
julia> mlc = MultiLeafCollimator(mlcx, mlcy)
2x3 MultiLeafCollimator 1: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 3: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
They can also be constructed by just specifying the edges, which sets the leaf positions to zero,
MultiLeafCollimator(mlcy)
Indexing and iterating through the MLC will produce a subset of the MLC, either returning Jaws
or another MultiLeafCollimator
,
julia> mlc[1]
Jaws{Float64}([-10.0, 10.0], [-5.0, 0.0])
julia> mlc[2:3]
2x2 MultiLeafCollimator 1: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
julia> @view mlc[1:2]
2x2 MultiLeafCollimator 1: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
Leaf positions can be accessed using the getpositions
,
julia> getpositions(mlc)
2×3 Matrix{Float64}: -10.0 -12.0 -23.0 10.0 4.0 -10.0
julia> getpositions(mlc, 1)
2-element Vector{Float64}: -10.0 10.0
Edge positions can be accessed using getedges
,
julia> getedges(mlc)
-5.0:5.0:10.0
julia> getedges(mlc, 1)
-5.0:5.0:0.0
julia> getedges(mlc, 1:2)
-5.0:5.0:5.0
Leaf positions can be set with setpositions!
and closed with closeleaves!
julia> closeleaves!(mlc)
2x3 MultiLeafCollimator 1: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 3: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
julia> mlc[1] = -5., 25
(-5.0, 25)
julia> mlc
2x3 MultiLeafCollimator 1: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 3: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
julia> mlcx = [-10. -12. -23. 10. 4. -10.];
julia> setpositions!(mlc, mlcx)
2x3 MultiLeafCollimator 1: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 2: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 3: ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
Bixels
Bixels are 2D elements denoting a rectangular section of the isoplane. Their position and width is in the IEC BLD coordinate system, scaled to the isoplane.
Bixels are constructed by specifing their position and width,
julia> bixel = Bixel(0., 0., 1., 1.)
Bixel{Float64}([0.0, 0.0], [1.0, 1.0])
A collection of bixels is used to build a fluence map. Most functions will take a list of bixels (AbstractVector{Bixel}
). These can either be constructed using the Bixel
constructor, or using one of the following bixel methods.
Bixel Grids
Bixel grids store bixels in a rectilinear grid, and behave as Matrix{Bixel}
. They can be constructed by supplying a vector or range of bixel edge positions,
julia> bixels = BixelGrid(-10.:5.:10, -10.:5.:10.)
4×4 BixelGrid{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}: Bixel{Float64}([-7.5, -7.5], [5.0, 5.0]) … Bixel{Float64}([-7.5, 7.5], [5.0, 5.0]) Bixel{Float64}([-2.5, -7.5], [5.0, 5.0]) Bixel{Float64}([-2.5, 7.5], [5.0, 5.0]) Bixel{Float64}([2.5, -7.5], [5.0, 5.0]) Bixel{Float64}([2.5, 7.5], [5.0, 5.0]) Bixel{Float64}([7.5, -7.5], [5.0, 5.0]) Bixel{Float64}([7.5, 7.5], [5.0, 5.0])
Bixel grids can also be constructed using the information from beam-limiting devices,
julia> jaws = Jaws([-5., 5.], [-10., 10.])
Jaws{Float64}([-5.0, 5.0], [-10.0, 10.0])
julia> bixels = BixelGrid(jaws, 5., 5.)
2×4 BixelGrid{Vector{Float64}, Vector{Float64}}: Bixel{Float64}([-2.5, -7.5], [5.0, 5.0]) … Bixel{Float64}([-2.5, 7.5], [5.0, 5.0]) Bixel{Float64}([2.5, -7.5], [5.0, 5.0]) Bixel{Float64}([2.5, 7.5], [5.0, 5.0])
They behave like matrices: they can be indexed (both linear and Cartesian indexing), and iterate through each bixel,
julia> bixels[3]
Bixel{Float64}([-2.5, -2.5], [5.0, 5.0])
julia> bixels[1, 2]
Bixel{Float64}([-2.5, -2.5], [5.0, 5.0])
They also have specialised methods for accessing grid axes,
julia> getaxes(bixels)
([-5.0, 0.0, 5.0], [-10.0, -5.0, 0.0, 5.0, 10.0])
julia> getaxes(bixels, 1)
3-element Vector{Float64}: -5.0 0.0 5.0
Bixels from Beam-Limiting Devices
In addition to the creation of bixel grids from beam-limiting devices, bixels_from_bld
creates a vector of bixels that span the open aperture of the beam-limiting device, e.g.
julia> bixels = bixels_from_bld(mlc, jaws)
4-element Vector{Bixel{Float64}}: Bixel{Float64}([-2.5, -2.5], [5.0, 5.0]) Bixel{Float64}([2.5, -2.5], [5.0, 5.0]) Bixel{Float64}([-2.5, 2.5], [5.0, 5.0]) Bixel{Float64}([2.0, 2.5], [4.0, 5.0])
Fluence
Fluence is computed using the fluence
method with bixel and beam-limiting devices as inputs,
julia> fluence(bixel, jaws)
1.0
These are available for all beam-limiting devices.
Fluence maps similarly are generated fluence
and fluence!
methods,
julia> Ψ = fluence(bixels, mlc)
4-element Vector{Float64}: 1.0 1.0 1.0 1.0
julia> fluence!(Ψ, bixels, mlc)
4-element Vector{Float64}: 1.0 1.0 1.0 1.0
They can also be computed in-place with fluence!
, avoiding memory allocation.