Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom values for brain_phantom #484

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Changes from 6 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
271d98f
Custom values for brain_phantom
gsahonero Sep 22, 2024
a67c5bd
Update Phantom.jl
gsahonero Sep 23, 2024
afbd05b
Introducing default brain phantom properties
gsahonero Sep 26, 2024
262bf14
Merge branch 'master' of https://github.com/gsahonero/KomaMRI.jl
gsahonero Sep 26, 2024
cf83a9e
Details on documentation
gsahonero Sep 26, 2024
f858ef1
Updating to remove unnecessary things
gsahonero Sep 26, 2024
0294f4b
Returning phantom to original code
gsahonero Sep 26, 2024
165b793
Resolving problems in brain phantom
gsahonero Sep 27, 2024
91d59f5
Merge branch 'master' of https://github.com/gsahonero/KomaMRI.jl
gsahonero Sep 27, 2024
6b990f4
Merge branch 'JuliaHealth:master' into master
gsahonero Sep 27, 2024
5b6e25d
Avoiding flat arrays.
gsahonero Oct 4, 2024
4020c3d
Merge branch 'JuliaHealth:master' into master
gsahonero Oct 4, 2024
4e4896b
Merge branch 'master' into master
cncastillo Nov 1, 2024
3689518
Update Phantom.jl
gsahonero Nov 9, 2024
9bfe36b
Merge branch 'master' into master
cncastillo Nov 13, 2024
9cc9d29
Update KomaMRIBase/src/datatypes/Phantom.jl
gsahonero Nov 15, 2024
1b9aa93
Update KomaMRIBase/src/datatypes/Phantom.jl
gsahonero Nov 15, 2024
bd6b91e
Update KomaMRIBase/src/datatypes/Phantom.jl
gsahonero Nov 15, 2024
f55d387
Update KomaMRIBase/src/datatypes/Phantom.jl
gsahonero Nov 15, 2024
ecc9bbe
Update KomaMRIBase/src/datatypes/Phantom.jl
gsahonero Nov 15, 2024
1079053
Requested changes
gsahonero Dec 11, 2024
b843b60
Removing a println
gsahonero Dec 11, 2024
e61cd85
Reducing lines
gsahonero Dec 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
265 changes: 152 additions & 113 deletions KomaMRIBase/src/datatypes/Phantom.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ a property value representing a spin. This struct serves as an input for the sim
- `Dλ2`: (`::AbstractVector{T<:Real}`) spin Dλ2 (diffusion) parameter vector
- `Dθ`: (`::AbstractVector{T<:Real}`) spin Dθ (diffusion) parameter vector
- `motion`: (`::AbstractMotion{T<:Real}`) motion
- `Mz`: (`::AbstractVector{ComplexF32}`) transverse magnetization parameter vector, only for storage purposes
- `Mxy`: (`::AbstractVector{ComplexF32}`) longitudinal magnetization parameter vector, only for storage purposes

# Returns
- `obj`: (`::Phantom`) Phantom struct
Expand All @@ -29,7 +31,7 @@ julia> obj = Phantom(x=[0.0])
julia> obj.ρ
```
"""
@with_kw mutable struct Phantom{T<:Real}
@with_kw mutable struct Phantom{T<:Number}
cncastillo marked this conversation as resolved.
Show resolved Hide resolved
name::String = "spins"
x :: AbstractVector{T}
y::AbstractVector{T} = zeros(eltype(x), size(x))
Expand All @@ -48,6 +50,8 @@ julia> obj.ρ
#Diff::Vector{DiffusionModel} #Diffusion map
#Motion
motion::AbstractMotion{T} = NoMotion{eltype(x)}()
Mxy::AbstractVector{ComplexF32} = zeros(eltype(x), size(x)) .+ 0im
Mz::AbstractVector{ComplexF32} = zeros(eltype(x), size(x)) .+ 0im
cncastillo marked this conversation as resolved.
Show resolved Hide resolved
end

const NON_STRING_PHANTOM_FIELDS = Iterators.filter(x -> fieldtype(Phantom, x) != String, fieldnames(Phantom))
Expand Down Expand Up @@ -195,6 +199,7 @@ function heart_phantom(;
return phantom
end


gsahonero marked this conversation as resolved.
Show resolved Hide resolved
"""
phantom = brain_phantom2D(;axis="axial", ss=4)

Expand All @@ -212,7 +217,7 @@ Default ss=4 sample spacing is 2 mm. Original file (ss=1) sample spacing is .5 m
- `axis`: (`::String`, `="axial"`, opts=[`"axial"`, `"coronal"`, `"sagittal"`]) orientation of the phantom
- `ss`: (`::Integer or ::Vector{Integer}`, `=4`) subsampling parameter for all axes if scaler, per axis if 2 element vector [ssx, ssy]
- `us`: (`::Integer or ::Vector{Integer}`, `=1`) upsampling parameter for all axes if scaler, per axis if 2 element vector [usx, usy], if used ss is set to ss=1

- `tissue_properties`: (`::Dict`, `=nothing`) phantom tissue properties in ms and Hz considering the available tissues
gsahonero marked this conversation as resolved.
Show resolved Hide resolved

# Returns
- `obj`: (`::Phantom`) Phantom struct
Expand All @@ -223,11 +228,28 @@ julia> obj = brain_phantom2D(; axis="sagittal", ss=1)

julia> obj = brain_phantom2D(; axis="axial", us=[1, 2])

julia> phantom_values =
Dict(
# T1, T2, T2*, ρ, Δw
"CSF" => [2569, 329, 58, 1, 0],
"GM" => [1153, 83, 69, 0.86, 0],
"WM" => [746, 70, 61, 0.77, 0],
"FAT1" => [0, 0, 0, 0, 0],
"MUSCLE" => [0, 0, 0, 0, 0],
"SKIN/MUSCLE" => [0, 0, 0, 0, 0],
"SKULL" => [0, 0, 0, 0, 0],
"VESSELS" => [0, 0, 0, 0, 0],
"FAT2" => [0, 0, 0, 0, 0],
"DURA" => [0, 0, 0, 0, 0],
"MARROW" => [0, 0, 0, 0, 0])
julia> obj = brain_phantom2D(; tissue_properties=phantom_values)
gsahonero marked this conversation as resolved.
Show resolved Hide resolved

julia> plot_phantom_map(obj, :ρ)
```
"""
function brain_phantom2D(; axis="axial", ss=4, us=1)
function brain_phantom2D(; axis="axial", ss=4, us=1, tissue_properties = nothing)
# check and filter input
# check more spins
gsahonero marked this conversation as resolved.
Show resolved Hide resolved
ssx, ssy, ssz, usx, usy, usz = check_phantom_arguments(2, ss, us)

# Get data from .mat file
Expand All @@ -247,59 +269,8 @@ function brain_phantom2D(; axis="axial", ss=4, us=1)
y = (-FOVy / 2):Δy:(FOVy / 2) #spin coordinates
x, y = x .+ y' * 0, x * 0 .+ y' #grid points

# Define spin property vectors
T2 =
(class .== 23) * 329 .+ #CSF
(class .== 46) * 83 .+ #GM
(class .== 70) * 70 .+ #WM
(class .== 93) * 70 .+ #FAT1
(class .== 116) * 47 .+ #MUSCLE
(class .== 139) * 329 .+ #SKIN/MUSCLE
(class .== 162) * 0 .+ #SKULL
(class .== 185) * 0 .+ #VESSELS
(class .== 209) * 70 .+ #FAT2
(class .== 232) * 329 .+ #DURA
(class .== 255) * 70 #MARROW
T2s =
(class .== 23) * 58 .+ #CSF
(class .== 46) * 69 .+ #GM
(class .== 70) * 61 .+ #WM
(class .== 93) * 58 .+ #FAT1
(class .== 116) * 30 .+ #MUSCLE
(class .== 139) * 58 .+ #SKIN/MUSCLE
(class .== 162) * 0 .+ #SKULL
(class .== 185) * 0 .+ #VESSELS
(class .== 209) * 61 .+ #FAT2
(class .== 232) * 58 .+ #DURA
(class .== 255) * 61 #MARROW
T1 =
(class .== 23) * 2569 .+ #CSF
(class .== 46) * 833 .+ #GM
(class .== 70) * 500 .+ #WM
(class .== 93) * 350 .+ #FAT1
(class .== 116) * 900 .+ #MUSCLE
(class .== 139) * 569 .+ #SKIN/MUSCLE
(class .== 162) * 0 .+ #SKULL
(class .== 185) * 0 .+ #VESSELS
(class .== 209) * 500 .+ #FAT2
(class .== 232) * 2569 .+ #DURA
(class .== 255) * 500 #MARROW
ρ =
(class .== 23) * 1 .+ #CSF
(class .== 46) * 0.86 .+ #GM
(class .== 70) * 0.77 .+ #WM
(class .== 93) * 1 .+ #FAT1
(class .== 116) * 1 .+ #MUSCLE
(class .== 139) * 1 .+ #SKIN/MUSCLE
(class .== 162) * 0 .+ #SKULL
(class .== 185) * 0 .+ #VESSELS
(class .== 209) * 0.77 .+ #FAT2
(class .== 232) * 1 .+ #DURA
(class .== 255) * 0.77 #MARROW
Δw_fat = -220 * 2π
Δw =
(class .== 93) * Δw_fat .+ #FAT1
(class .== 209) * Δw_fat #FAT2
# Get tissue properties
T1, T2, T2s, ρ, Δw = default_brain_tissue_properties(class, tissue_properties)
T1 = T1 * 1e-3
T2 = T2 * 1e-3
T2s = T2s * 1e-3
Expand Down Expand Up @@ -336,6 +307,7 @@ Default ss=4 sample spacing is 2 mm. Original file (ss=1) sample spacing is .5 m
- `ss`: (`::Integer or ::Vector{Integer}`, `=4`) subsampling parameter for all axes if scaler, per axis if 3 element vector [ssx, ssy, ssz]
- `us`: (`::Integer or ::Vector{Integer}`, `=1`) upsampling parameter for all axes if scaler, per axis if 3 element vector [usx, usy, usz]
- `start_end`: (`::Vector{Integer}`, `=[160,200]`) z index range of presampled phantom, 180 is center
- `tissue_properties`: (`::Dict`, `=nothing`) phantom tissue properties in ms and Hz considering the available tissues

# Returns
- `obj`: (`::Phantom`) 3D Phantom struct
Expand All @@ -346,13 +318,29 @@ julia> obj = brain_phantom3D(; ss=5)

julia> obj = brain_phantom3D(; us=[2, 2, 1])

julia> phantom_values =
Dict(
# T1, T2, T2*, ρ, Δw
"CSF" => [2569, 329, 58, 1, 0],
"GM" => [1153, 83, 69, 0.86, 0],
"WM" => [746, 70, 61, 0.77, 0],
"FAT1" => [0, 0, 0, 0, 0],
"MUSCLE" => [0, 0, 0, 0, 0],
"SKIN/MUSCLE" => [0, 0, 0, 0, 0],
"SKULL" => [0, 0, 0, 0, 0],
"VESSELS" => [0, 0, 0, 0, 0],
"FAT2" => [0, 0, 0, 0, 0],
"DURA" => [0, 0, 0, 0, 0],
"MARROW" => [0, 0, 0, 0, 0])
julia> obj = brain_phantom3D(; tissue_properties=phantom_values)

julia> plot_phantom_map(obj, :ρ)
```
"""
function brain_phantom3D(; ss=4, us=1, start_end=[160, 200])
function brain_phantom3D(; ss=4, us=1, start_end=[160, 200], tissue_properties=nothing)
# check and filter input
ssx, ssy, ssz, usx, usy, usz = check_phantom_arguments(3, ss, us)

gsahonero marked this conversation as resolved.
Show resolved Hide resolved
# Get data from .mat file
path = @__DIR__
data = MAT.matread(path * "/phantom/brain3D.mat")
Expand All @@ -377,60 +365,9 @@ function brain_phantom3D(; ss=4, us=1, start_end=[160, 200])
x = 1 * xx .+ 0 * yy .+ 0 * zz
y = 0 * xx .+ 1 * yy .+ 0 * zz
z = 0 * xx .+ 0 * yy .+ 1 * zz

# Define spin property vectors
T2 =
(class .== 23) * 329 .+ #CSF
(class .== 46) * 83 .+ #GM
(class .== 70) * 70 .+ #WM
(class .== 93) * 70 .+ #FAT1
(class .== 116) * 47 .+ #MUSCLE
(class .== 139) * 329 .+ #SKIN/MUSCLE
(class .== 162) * 0 .+ #SKULL
(class .== 185) * 0 .+ #VESSELS
(class .== 209) * 70 .+ #FAT2
(class .== 232) * 329 .+ #DURA
(class .== 255) * 70 #MARROW
T2s =
(class .== 23) * 58 .+ #CSF
(class .== 46) * 69 .+ #GM
(class .== 70) * 61 .+ #WM
(class .== 93) * 58 .+ #FAT1
(class .== 116) * 30 .+ #MUSCLE
(class .== 139) * 58 .+ #SKIN/MUSCLE
(class .== 162) * 0 .+ #SKULL
(class .== 185) * 0 .+ #VESSELS
(class .== 209) * 61 .+ #FAT2
(class .== 232) * 58 .+ #DURA
(class .== 255) * 61 #MARROW
T1 =
(class .== 23) * 2569 .+ #CSF
(class .== 46) * 833 .+ #GM
(class .== 70) * 500 .+ #WM
(class .== 93) * 350 .+ #FAT1
(class .== 116) * 900 .+ #MUSCLE
(class .== 139) * 569 .+ #SKIN/MUSCLE
(class .== 162) * 0 .+ #SKULL
(class .== 185) * 0 .+ #VESSELS
(class .== 209) * 500 .+ #FAT2
(class .== 232) * 2569 .+ #DURA
(class .== 255) * 500 #MARROW
ρ =
(class .== 23) * 1 .+ #CSF
(class .== 46) * 0.86 .+ #GM
(class .== 70) * 0.77 .+ #WM
(class .== 93) * 1 .+ #FAT1
(class .== 116) * 1 .+ #MUSCLE
(class .== 139) * 1 .+ #SKIN/MUSCLE
(class .== 162) * 0 .+ #SKULL
(class .== 185) * 0 .+ #VESSELS
(class .== 209) * 0.77 .+ #FAT2
(class .== 232) * 1 .+ #DURA
(class .== 255) * 0.77 #MARROW
Δw_fat = -220 * 2π
Δw =
(class .== 93) * Δw_fat .+ #FAT1
(class .== 209) * Δw_fat #FAT2

# Get tissue properties
T1, T2, T2s, ρ, Δw = default_brain_tissue_properties(class, tissue_properties)
T1 = T1 * 1e-3
T2 = T2 * 1e-3
T2s = T2s * 1e-3
Expand Down Expand Up @@ -482,7 +419,7 @@ function pelvis_phantom2D(; ss=4, us=1)

# subsample or upsample the phantom data
class = repeat(data["pelvis3D_slice"][1:ssx:end, 1:ssy:end]; inner=[usx, usy])

gsahonero marked this conversation as resolved.
Show resolved Hide resolved
# Define spin position vectors
Δx = .5e-3 * ssx / usx
Δy = .5e-3 * ssy / usy
Expand Down Expand Up @@ -612,5 +549,107 @@ function check_phantom_arguments(nd, ss, us)
ssy = ss[2]
end
end

return ssx, ssy, ssz, usx, usy, usz
end

"""
T1, T2, T2s, ρ, Δw = default_brain_tissue_properties(class, tissue_properties = nothing)

This function returns the default brain tissue properties using a class identifier Matrix
# Arguments
- `class` : (`::Matrix`) the class identifier matrix of the phantom
- `tissue_properties` : (`::Dict`, `=nothing`) phantom tissue properties in ms and Hz considering the available tissues

# Returns
- `T1, T2, T2s, ρ, Δw`: (`::Matrix`) matrices of the same size of class with the tissues properties information

# Examples
```julia-repl
julia> T1, T2, T2s, ρ, Δw = default_brain_tissue_properties(class, tissue_properties)

julia> T1, T2, T2s, ρ, Δw = default_brain_tissue_properties(class)
```
"""
function default_brain_tissue_properties(class, tissue_properties = nothing)
gsahonero marked this conversation as resolved.
Show resolved Hide resolved
if isnothing(tissue_properties)
# Load default tissue properties
tissue_properties = Dict(
# T1, T2, T2*, ρ, Δw
"CSF" => [2569, 329, 58, 1, 0],
"GM" => [833, 83, 69, 0.86, 0],
"WM" => [500, 70, 61, 0.77, 0],
"FAT1" => [350, 70, 58, 1, -220],
"MUSCLE" => [900, 47, 30, 1, 0],
"SKIN/MUSCLE" => [569, 329, 58, 1, 0],
"SKULL" => [0, 0, 0, 0, 0],
"VESSELS" => [0, 0, 0, 0, 0],
"FAT2" => [500, 70, 61, 0.77, -220],
"DURA" => [2569, 329, 58, 1, 0],
"MARROW" => [500, 70, 61, 0.77, 0])
# Define spin property vectors
end
gsahonero marked this conversation as resolved.
Show resolved Hide resolved
T1 =
(class .== 23) * tissue_properties["CSF"][1] .+ #CSF
(class .== 46) * tissue_properties["GM"][1] .+ #GM
(class .== 70) * tissue_properties["WM"][1] .+ #WM
(class .== 93) * tissue_properties["FAT1"][1] .+ #FAT1
(class .== 116) * tissue_properties["MUSCLE"][1] .+ #MUSCLE
(class .== 139) * tissue_properties["SKIN/MUSCLE"][1] .+ #SKIN/MUSCLE
(class .== 162) * tissue_properties["SKULL"][1] .+ #SKULL
(class .== 185) * tissue_properties["VESSELS"][1] .+ #VESSELS
(class .== 209) * tissue_properties["FAT2"][1] .+ #FAT2
(class .== 232) * tissue_properties["DURA"][1] .+ #DURA
(class .== 255) * tissue_properties["MARROW"][1] #MARROW
T2 =
(class .== 23) * tissue_properties["CSF"][2] .+ #CSF
(class .== 46) * tissue_properties["GM"][2] .+ #GM
(class .== 70) * tissue_properties["WM"][2] .+ #WM
(class .== 93) * tissue_properties["FAT1"][2] .+ #FAT1
(class .== 116) * tissue_properties["MUSCLE"][2] .+ #MUSCLE
(class .== 139) * tissue_properties["SKIN/MUSCLE"][2] .+ #SKIN/MUSCLE
(class .== 162) * tissue_properties["SKULL"][2] .+ #SKULL
(class .== 185) * tissue_properties["VESSELS"][2] .+ #VESSELS
(class .== 209) * tissue_properties["FAT2"][2] .+ #FAT2
(class .== 232) * tissue_properties["DURA"][2] .+ #DURA
(class .== 255) * tissue_properties["MARROW"][2] #MARROW
T2s =
(class .== 23) * tissue_properties["CSF"][3] .+ #CSF
(class .== 46) * tissue_properties["GM"][3] .+ #GM
(class .== 70) * tissue_properties["WM"][3] .+ #WM
(class .== 93) * tissue_properties["FAT1"][3] .+ #FAT1
(class .== 116) * tissue_properties["MUSCLE"][3] .+ #MUSCLE
(class .== 139) * tissue_properties["SKIN/MUSCLE"][3] .+ #SKIN/MUSCLE
(class .== 162) * tissue_properties["SKULL"][3] .+ #SKULL
(class .== 185) * tissue_properties["VESSELS"][3] .+ #VESSELS
(class .== 209) * tissue_properties["FAT2"][3] .+ #FAT2
(class .== 232) * tissue_properties["DURA"][3] .+ #DURA
(class .== 255) * tissue_properties["MARROW"][3] #MARROW

ρ =
(class .== 23) * tissue_properties["CSF"][4] .+ #CSF
(class .== 46) * tissue_properties["GM"][4] .+ #GM
(class .== 70) * tissue_properties["WM"][4] .+ #WM
(class .== 93) * tissue_properties["FAT1"][4] .+ #FAT1
(class .== 116) * tissue_properties["MUSCLE"][4] .+ #MUSCLE
(class .== 139) * tissue_properties["SKIN/MUSCLE"][4] .+ #SKIN/MUSCLE
(class .== 162) * tissue_properties["SKULL"][4] .+ #SKULL
(class .== 185) * tissue_properties["VESSELS"][4] .+ #VESSELS
(class .== 209) * tissue_properties["FAT2"][4] .+ #FAT2
(class .== 232) * tissue_properties["DURA"][4] .+ #DURA
(class .== 255) * tissue_properties["MARROW"][4] #MARROW

Δw =
(class .== 23) * tissue_properties["CSF"][5] .+ #CSF
(class .== 46) * tissue_properties["GM"][5] .+ #GM
(class .== 70) * tissue_properties["WM"][5] .+ #WM
(class .== 93) * tissue_properties["FAT1"][5] .+ #FAT1
(class .== 116) * tissue_properties["MUSCLE"][5] .+ #MUSCLE
(class .== 139) * tissue_properties["SKIN/MUSCLE"][5] .+ #SKIN/MUSCLE
(class .== 162) * tissue_properties["SKULL"][5] .+ #SKULL
(class .== 185) * tissue_properties["VESSELS"][5] .+ #VESSELS
(class .== 209) * tissue_properties["FAT2"][5] .+ #FAT2
(class .== 232) * tissue_properties["DURA"][5] .+ #DURA
(class .== 255) * tissue_properties["MARROW"][5] #MARROW
return T1, T2, T2s, ρ, Δw
end
gsahonero marked this conversation as resolved.
Show resolved Hide resolved
Loading