Skip to content

Commit

Permalink
Merge pull request #422 from JuliaHealth/fix-type-piracy
Browse files Browse the repository at this point in the history
Fixing issues in Julia 1.11 and Julia 1.12
  • Loading branch information
cncastillo authored Jul 5, 2024
2 parents 5b6e9fb + 9534b4c commit eb05128
Show file tree
Hide file tree
Showing 24 changed files with 104 additions and 113 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml → .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
tags: '*'
jobs:
ci:
if: "!contains(github.event.head_commit.message, '[skip ci]')"
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Nightly
name: PreRelease
on:
pull_request:
branches:
Expand All @@ -8,17 +8,17 @@ on:
- master
tags: '*'
jobs:
nightly:
if: "contains(github.event.head_commit.message, '[nightly]')"
prerelease:
if: ${{ contains( github.event.pull_request.labels.*.name, 'pre-release' ) }}
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
version:
- 'nightly' # Latest version of Julia under development (you can expect many packages not to work with this version)
os: [ubuntu-latest, windows-latest, macos-latest]
- 'pre' # Latest version of Julia under development (you can expect many packages not to work with this version)
os: [ubuntu-latest, windows-latest, macos-12] # macos-latest] <- M1 Mac was generating problems #386, commented for now
arch: [x64]
include:
- os: ubuntu-latest
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ examples/5.koma_paper/comparison_accuracy/**/*.mrd
examples/5.koma_paper/mrf/**/*.mrd
examples/5.koma_paper/comparison_accuracy/**/*.mat
examples/5.koma_paper/comparison_accuracy/**/*.h5
!examples/5.koma_paper/Manifest.toml
!examples/5.koma_paper/Manifest.toml
*_w.phantom
5 changes: 4 additions & 1 deletion KomaMRIBase/Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "KomaMRIBase"
uuid = "d0bc0b20-b151-4d03-b2a4-6ca51751cb9c"
authors = ["Carlos Castillo Passi <cncastillo@uc.cl>"]
version = "0.8.4"
version = "0.9.0"

[deps]
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
Expand All @@ -19,3 +19,6 @@ Parameters = "0.12"
Pkg = "1.4"
Reexport = "1"
julia = "1.9"

[workspace]
projects = ["test"]
28 changes: 3 additions & 25 deletions KomaMRIBase/src/datatypes/Sequence.jl
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,7 @@ Tells if the sequence `seq` has elements with ADC active, or active during time
is_ADC_on(x::Sequence) = any(x-> x > 0, x.ADC.N)
is_ADC_on(x::Sequence, t::AbstractVecOrMat) = begin
N = length(x)
ΔT = durs(x)
ts = cumsum([0 ; ΔT[1:end-1]])
ts = get_block_start_times(x)[1:end-1]
delays = x.ADC.delay
Ts = x.ADC.dur #delat+T
t0s = ts .+ delays
Expand Down Expand Up @@ -184,8 +183,7 @@ Tells if the sequence `seq` has elements with RF active, or active during time `
is_RF_on(x::Sequence) = any([sum(abs.(r.A)) for r = x.RF] .> 0)
is_RF_on(x::Sequence, t::AbstractVector) = begin
N = length(x)
ΔT = durs(x)
ts = cumsum([0 ; ΔT[1:end-1]])
ts = get_block_start_times(x)[1:end-1]
delays = x.RF.delay
Ts = x.RF.dur #dur = delat+T
t0s = ts .+ delays
Expand Down Expand Up @@ -263,26 +261,6 @@ Tells if the sequence `seq` is a delay.
"""
is_Delay(x::Sequence) = !(is_GR_on(x) || is_RF_on(x) || is_ADC_on(x))

"""
ΔT = durs(x::Sequence)
Returns the array of durations of sequence's blocks in [s].
# Arguments
- `x`: (`::Sequence`) Sequence struct
# Returns
- `ΔT`: (`::Vector{Real}`, `[s]`) array of durations of sequence's blocks
"""
durs(x::Sequence) = begin
# ΔT_GR = x.GR.dur
# ΔT_RF = x.RF.dur
# ΔT_ADC = x.ADC.dur
# ΔT_DUR = x.DUR
# ΔT = maximum([ΔT_GR ΔT_RF ΔT_ADC ΔT_DUR],dims=2)
x.DUR
end

"""
T = dur(x::Sequence)
Expand All @@ -294,7 +272,7 @@ The total duration of the sequence in [s].
# Returns
- `T`: (`::Real`, `[s]`) total duration of the sequence
"""
dur(x::Sequence) = sum(durs(x))
dur(x::Sequence) = sum(x.DUR)

"""
T0 = get_block_start_times(seq::Sequence)
Expand Down
8 changes: 4 additions & 4 deletions KomaMRIBase/src/datatypes/sequence/ADC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ directly without the need to iterate elementwise.
"""
getproperty(x::Vector{ADC}, f::Symbol) = begin
if f == :dur
T, delay = x.T, x.delay
ΔT = T .+ delay
ΔT
dur.(x)
elseif f in fieldnames(ADC)
getfield.(x, f)
else
getproperty.(x, f)
getfield(x, f)
end
end

Expand Down
49 changes: 24 additions & 25 deletions KomaMRIBase/src/datatypes/sequence/Grad.jl
Original file line number Diff line number Diff line change
Expand Up @@ -182,34 +182,34 @@ Base.show(io::IO, x::Grad) = begin
end

"""
y = getproperty(x::Vector{Grad}, f::Symbol)
y = getproperty(x::Matrix{Grad}, f::Symbol)
y = getproperty(x::Array{Grad}, f::Symbol)
Overloads Base.getproperty(). It is meant to access properties of the Grad vector `x`
directly without the need to iterate elementwise.
# Arguments
- `x`: (`::Vector{Grad}` or `::Matrix{Grad}`) vector or matrix of Grad structs
- `x`: (`::Array{Grad}`) vector or matrix of Grad structs
- `f`: (`::Symbol`, opts: [`:x`, `:y`, `:z`, `:T`, `:delay`, `:rise`, `:delay`, `:dur`,
`:A`, `f`]) input symbol that represents a property of the vector or matrix of Grad
structs
# Returns
- `y`: (`::Vector{Any}` or `::Matrix{Any}`) vector or matrix with the property defined
- `y`: (`::Array{Any}`) vector or matrix with the property defined
by the symbol `f` for all elements of the Grad vector or matrix `x`
"""
getproperty(x::Vector{Grad}, f::Symbol) = getproperty.(x, f)
getproperty(x::Matrix{Grad}, f::Symbol) = begin
getproperty(x::Array{Grad}, f::Symbol) = begin
if f == :x
x[1, :]
@view x[1, :]
elseif f == :y && size(x, 1) >= 2
x[2, :]
@view x[2, :]
elseif f == :z && size(x, 1) >= 3
x[3, :]
@view x[3, :]
elseif f == :dur
maximum(dur.(x); dims=1)[:]
dur(x)
elseif f in fieldnames(Grad)
getfield.(x, f)
else
getproperty.(x, f)
getfield(x, f)
end
end

Expand All @@ -221,17 +221,15 @@ function Base.isapprox(gr1::Grad, gr2::Grad)
end

# Gradient operations
*(x::Grad, α::Real) = Grad* x.A, x.T, x.rise, x.fall, x.delay)
*::Real, x::Grad) = Grad* x.A, x.T, x.rise, x.fall, x.delay)
function *(A::Matrix{Float64}, GR::Matrix{Grad})
N, M = size(GR)
return [sum(A[i, 1:N] .* GR[:, j]) for i in 1:N, j in 1:M]
end
# zeros(Grad, M, N)
Base.zero(::Type{Grad}) = Grad(0.0, 0.0)
# Rotation
Base.zero(::Grad) = Grad(0.0, 0.0)
size(g::Grad, i::Int64) = 1 #To fix [g;g;;] concatenation of Julia 1.7.3
/(x::Grad, α::Real) = Grad(x.A / α, x.T, x.rise, x.fall, x.delay)
*::Real, x::Grad) = Grad* x.A, x.T, x.rise, x.fall, x.delay)
+(x::Grad, y::Grad) = Grad(x.A .+ y.A, x.T, x.rise, x.fall, x.delay)
+(x::Array{Grad,1}, y::Array{Grad,1}) = [x[i] + y[i] for i in 1:length(x)]
# Others
*(x::Grad, α::Real) = Grad* x.A, x.T, x.rise, x.fall, x.delay)
/(x::Grad, α::Real) = Grad(x.A / α, x.T, x.rise, x.fall, x.delay)
-(x::Grad) = -1 * x
-(x::Grad, y::Grad) = Grad(x.A .- y.A, x.T, x.rise, x.fall, x.delay)

Expand All @@ -254,15 +252,16 @@ end
"""
y = dur(x::Grad)
y = dur(x::Vector{Grad})
y = dur(x::Matrix{Grad})
Duration time in [s] of Grad struct or Grad array. When the input is a gradient vector, then
the duration is the maximum duration of all the elements of the gradient vector.
Duration time in [s] of Grad struct or Grad Array.
# Arguments
- `x`: (`::Grad` or `::Vector{Grad}`) RF struct or RF array
- `x`: (`::Grad` or `::Vector{Grad}` or `::Matrix{Grad}`) Grad struct or Grad Array
# Returns
- `y`: (`::Float64`, `[s]`) duration of the RF struct or RF array
- `y`: (`::Float64`, `[s]`) duration of the Grad struct or Grad Array
"""
dur(x::Grad) = x.delay + x.rise + sum(x.T) + x.fall
dur(x::Vector{Grad}) = maximum(dur.(x); dims=1)[:]
dur(x::Vector{Grad}) = maximum(dur.(x); dims=1)[:]
dur(x::Matrix{Grad}) = maximum(dur.(x); dims=1)[:]
40 changes: 16 additions & 24 deletions KomaMRIBase/src/datatypes/sequence/RF.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,37 +71,31 @@ Base.show(io::IO, x::RF) = begin
end

"""
y = getproperty(x::Vector{RF}, f::Symbol)
y = getproperty(x::Matrix{RF}, f::Symbol)
y = getproperty(x::Array{RF}, f::Symbol)
Overloads Base.getproperty(). It is meant to access properties of the RF vector `x`
directly without the need to iterate elementwise.
# Arguments
- `x`: (`::Vector{RF}` or `::Matrix{RF}`) vector or matrix of RF structs
- `x`: (`::Array{RF}`) vector or matrix of RF structs
- `f`: (`::Symbol`, opts: [`:A`, `:Bx`, `:By`, `:T`, `:Δf`, `:delay` and `:dur`]) input
symbol that represents a property of the vector or matrix of RF structs
# Returns
- `y`: (`::Vector{Any}` or `::Matrix{Any}`) vector with the property defined by the
- `y`: (`::Array{Any}`) vector or matrix with the property defined by the
symbol `f` for all elements of the RF vector or matrix `x`
"""
getproperty(x::Vector{RF}, f::Symbol) = getproperty.(x, f)
getproperty(x::Matrix{RF}, f::Symbol) = begin
if f == :Bx
real.(getproperty.(x, :A))
real.(getfield.(x, :A))
elseif f == :By
imag.(getproperty.(x, :A))
elseif f == :Δf
getproperty.(x, :Δf)
elseif f == :T || f == :delay
getproperty.(x[1, :], f)
imag.(getfield.(x, :A))
elseif f == :dur
T, delay = x.T, x.delay
ΔT = [sum(t) for t in T] .+ delay
ΔT
dur(x)
elseif f in fieldnames(RF)
getfield.(x, f)
else
getproperty.(x, f)
getfield(x, f)
end
end

Expand All @@ -118,22 +112,20 @@ size(r::RF, i::Int64) = 1 #To fix [r;r;;] concatenation of Julia 1.7.3

"""
y = dur(x::RF)
y = dur(x::Array{RF,1})
y = dur(x::Array{RF,2})
y = dur(x::Vector{RF})
y = dur(x::Matrix{RF})
Duration time in [s] of RF struct or RF array.
Duration time in [s] of RF struct or RF Array.
# Arguments
- `x`: (`::RF` or `::Array{RF,1}` or `::Array{RF,2}`) RF struct or RF array
- `x`: (`::RF` or `::Vector{RF}` or `::Matrix{RF}`) RF struct or RF array
# Returns
- `y`: (`::Float64`, [`s`]) duration of the RF struct or RF array
"""
dur(x::RF) = sum(x.T)
dur(x::Array{RF,1}) = sum(sum(x[i].T) for i in 1:size(x, 1))
function dur(x::Array{RF,2})
return maximum(sum([sum(x[i, j].T) for i in 1:size(x, 1), j in 1:size(x, 2)]; dims=2))
end
dur(x::RF) = x.delay + sum(x.T)
dur(x::Vector{RF}) = maximum(dur.(x); dims=1)[:]
dur(x::Matrix{RF}) = maximum(dur.(x); dims=1)[:]

"""
rf = RF_fun(f::Function, T::Real, N::Int64)
Expand Down
15 changes: 8 additions & 7 deletions KomaMRIBase/src/sequences/PulseDesigner.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ julia> plot_seq(seq)
"""
function RF_hard(B1, T, sys::Scanner; G=[0, 0, 0], Δf=0)
ζ = sum(G) / sys.Smax
gr = reshape([Grad(G[1], T, ζ); Grad(G[2], T, ζ); Grad(G[3], T ,ζ)], :, 1)
rf = reshape([RF(B1, T, Δf, ζ)], :, 1)
gr = [Grad(G[1], T, ζ); Grad(G[2], T, ζ); Grad(G[3], T ,ζ) ;;]
rf = [RF(B1, T, Δf, ζ) ;;]
return Sequence(gr, rf)
end

Expand Down Expand Up @@ -159,9 +159,10 @@ function EPI(FOV::Real, N::Integer, sys::Scanner)
*string(round(1/*Gmax*FOV),digits=2))*" us.") : 0
ϵ1 = Δτ/(Δτ+ζ)
#EPI base
EPI = Sequence(vcat(
[mod(i,2)==0 ? Grad(Ga*(-1)^(i/2),Ta,ζ) : Grad(0.,Δτ,ζ) for i=0:2*Ny-2], #Gx
[mod(i,2)==1 ? ϵ1*Grad(Ga,Δτ,ζ) : Grad(0.,Ta,ζ) for i=0:2*Ny-2])) #Gy
GR = zeros(Grad, 3, length(0:2*Ny-2))
GR.x .= [mod(i,2)==0 ? Grad(Ga*(-1)^(i/2),Ta,ζ) : Grad(0.,Δτ,ζ) for i=0:2*Ny-2]
GR.y .= [mod(i,2)==1 ? ϵ1*Grad(Ga,Δτ,ζ) : Grad(0.,Ta,ζ) for i=0:2*Ny-2]
EPI = Sequence(GR)
EPI.ADC = [mod(i,2)==1 ? ADC(0,Δτ,ζ) : ADC(N,Ta,ζ) for i=0:2*Ny-2]
# Relevant parameters
Δfx_pix = 1/Ta
Expand All @@ -173,8 +174,8 @@ function EPI(FOV::Real, N::Integer, sys::Scanner)
# println("Pixel Δf in phase direction $(round(Δfx_pix_phase,digits=2)) Hz")
#Pre-wind and wind gradients
ϵ2 = Ta/(Ta+ζ)
PHASE = Sequence(reshape(1/2*[Grad( -Ga, Ta, ζ); ϵ2*Grad(-Ga, Ta, ζ)],:,1)) #This needs to be calculated differently
DEPHASE = Sequence(reshape(1/2*[Grad((-1)^N*Ga, Ta, ζ); ϵ2*Grad(-Ga, Ta, ζ)],:,1)) #for even N
PHASE = Sequence(1/2*[Grad( -Ga, Ta, ζ); ϵ2*Grad(-Ga, Ta, ζ); Grad(0.,0.);;]) #This needs to be calculated differently
DEPHASE = Sequence(1/2*[Grad((-1)^N*Ga, Ta, ζ); ϵ2*Grad(-Ga, Ta, ζ); Grad(0.,0.);;]) #for even N
seq = PHASE+EPI+DEPHASE
#Saving parameters
seq.DEF = Dict("Nx"=>Nx,"Ny"=>Ny,"Nz"=>1,"Name"=>"epi")
Expand Down
1 change: 1 addition & 0 deletions KomaMRIBase/test/Project.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[deps]
KomaMRIBase = "d0bc0b20-b151-4d03-b2a4-6ca51751cb9c"
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a"
Expand Down
10 changes: 5 additions & 5 deletions KomaMRIBase/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ using TestItems, TestItemRunner

@testset "Rot_and_Concat" begin
# Rotation 2D case
A1, A2, T, t = rand(4)
A1, A2, A3, T, t = rand(5)
s = Sequence([Grad(A1,T);
Grad(A2,T)])
Grad(A2,T);
Grad(A3,T);;])
θ = π*t
R = rotz(θ)
s2 = R*s #Matrix-Matrix{Grad} multiplication
Expand Down Expand Up @@ -96,7 +97,6 @@ using TestItems, TestItemRunner
# Test Grad operations
α = 3
gradt = α * grad
@test size(grad, 1) == 1
@test gradt.A α * grad.A
gradt = grad * α
@test gradt.A α * grad.A
Expand Down Expand Up @@ -165,8 +165,8 @@ using TestItems, TestItemRunner
@test dur(rf) rf.T
B1x, B1y, B2x, B2y, B3x, B3y, T1, T2, T3 = rand(9)
rf1, rf2, rf3 = RF(B1x + im*B1y, T1), RF(B1x + im*B1y, T2), RF(B3x + im*B3y, T3)
rv = [rf1; rf2; rf3]
@test dur(rv) sum(dur.(rv))
rv = [rf1; rf2; rf3 ;;]
@test dur(rv) maximum(dur.(rv); dims=1)

end

Expand Down
Loading

1 comment on commit eb05128

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KomaMRI Benchmarks

Benchmark suite Current: eb05128 Previous: 5b6e9fb Ratio
MRI Lab/Bloch/CPU/2 thread(s) 1905493127.5 ns 1533407266.5 ns 1.24
MRI Lab/Bloch/CPU/4 thread(s) 914487178 ns 945216808 ns 0.97
MRI Lab/Bloch/CPU/8 thread(s) 814946114 ns 882899126 ns 0.92
MRI Lab/Bloch/CPU/1 thread(s) 3299300532 ns 3215848346.5 ns 1.03
MRI Lab/Bloch/GPU/CUDA 155313870 ns 153244287.5 ns 1.01
MRI Lab/Bloch/GPU/oneAPI 27987109817 ns 27470305723 ns 1.02
MRI Lab/Bloch/GPU/Metal 3394142854 ns 3258257667 ns 1.04
MRI Lab/Bloch/GPU/AMDGPU 1755297484 ns 1759079282 ns 1.00
Slice Selection 3D/Bloch/CPU/2 thread(s) 3786600886 ns 3351480010 ns 1.13
Slice Selection 3D/Bloch/CPU/4 thread(s) 1794912707 ns 1780232282 ns 1.01
Slice Selection 3D/Bloch/CPU/8 thread(s) 1220462267 ns 1209111139 ns 1.01
Slice Selection 3D/Bloch/CPU/1 thread(s) 5938874198 ns 5198071177 ns 1.14
Slice Selection 3D/Bloch/GPU/CUDA 270408353 ns 265341221.5 ns 1.02
Slice Selection 3D/Bloch/GPU/oneAPI 2166473718.5 ns 2180574102 ns 0.99
Slice Selection 3D/Bloch/GPU/Metal 1392987166 ns 1136992729 ns 1.23
Slice Selection 3D/Bloch/GPU/AMDGPU 757974598 ns 727557861 ns 1.04

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.