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

New Motion #442

Merged
merged 100 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
2b491ff
Initial commit
pvillacorta Jul 11, 2024
b948d49
Delete `Static`
pvillacorta Jul 11, 2024
8f2ead2
Merge branch 'master' into new-motion
pvillacorta Jul 11, 2024
7ad003e
Apply suggested change by @rkierulf
pvillacorta Aug 1, 2024
447cbf7
Merge branch 'master' into new-motion
pvillacorta Aug 1, 2024
2804413
Solve bug
pvillacorta Aug 1, 2024
596af23
Enable all testsitems
pvillacorta Aug 1, 2024
fe9c8c2
Suggested changes
pvillacorta Aug 8, 2024
79596ad
Solve bug
pvillacorta Aug 9, 2024
ea91613
Solve bug
pvillacorta Aug 9, 2024
e10660f
Export `AbstractMotionList`
pvillacorta Aug 12, 2024
211337f
Remove periodic motions from docs
pvillacorta Aug 12, 2024
c78838e
Update `contracting_ring.phantom` example
pvillacorta Aug 12, 2024
c603fd0
Recover `tmp` variable for now
pvillacorta Aug 13, 2024
a21e3d7
Solve docs bug
pvillacorta Aug 13, 2024
76895c2
Update docs to pass CI
pvillacorta Aug 13, 2024
056c615
Docstrings to pass CI
pvillacorta Aug 14, 2024
4901df7
Test `get_spin_coords` in core
pvillacorta Aug 19, 2024
130a7f1
Continue testing
pvillacorta Aug 19, 2024
b4ac68e
Correct bug
pvillacorta Aug 19, 2024
5b59214
Add SimpleMotion test
pvillacorta Aug 19, 2024
0aa8540
Solve bug
pvillacorta Aug 19, 2024
36f96be
Try again...
pvillacorta Aug 19, 2024
02c539d
Again...
pvillacorta Aug 19, 2024
25360e2
Check if only fails with oneAPI
pvillacorta Aug 19, 2024
0d8a541
Try now
pvillacorta Aug 19, 2024
59d6ecc
Aux comments
pvillacorta Aug 19, 2024
0d2c134
Try with simple motion
pvillacorta Aug 19, 2024
2cbfa29
comments
pvillacorta Aug 19, 2024
77b9530
Recover to initial state
pvillacorta Aug 19, 2024
b5609c6
Merge branch 'master' into new-motion
pvillacorta Aug 19, 2024
0416bb0
Comments
pvillacorta Aug 19, 2024
b268578
More comments
pvillacorta Aug 19, 2024
c32b9bb
Try again
pvillacorta Aug 19, 2024
b90b791
Merge branch 'master' into new-motion
pvillacorta Aug 20, 2024
648a3d9
Merge branch 'master' into new-motion
cncastillo Aug 20, 2024
2995074
Big change
pvillacorta Aug 23, 2024
ee24363
Merge branch 'new-motion' of https://github.com/JuliaHealth/KomaMRI.j…
pvillacorta Aug 23, 2024
725e68a
Try again to test cpu multi-thread error
pvillacorta Aug 24, 2024
057ba72
Docstrings to pass CI
pvillacorta Aug 24, 2024
a1330a4
Solve multi-thread bug
pvillacorta Aug 24, 2024
8e44e49
Solve bug, now it is
pvillacorta Aug 24, 2024
53c1f6b
Merge branch 'master' into new-motion
pvillacorta Aug 24, 2024
0121d2d
Solve docs CI?
pvillacorta Aug 24, 2024
c63aa40
Compare MotionLists' lengths
pvillacorta Aug 26, 2024
d550bcd
Solve bugs
pvillacorta Aug 26, 2024
8db53d4
Auxiliary `length` method for SpinRanges
pvillacorta Aug 26, 2024
d7a3ed4
Solve bugs for flow
pvillacorta Aug 27, 2024
fd125e7
Merge branch 'master' into new-motion
pvillacorta Aug 27, 2024
afa7c83
Update docstrings
pvillacorta Aug 28, 2024
5d5a9a1
Fix some docstrings
pvillacorta Aug 29, 2024
36bc578
Remove unnecessary docstring
pvillacorta Aug 29, 2024
71960f7
Try to include docstring of `Translate` function
pvillacorta Aug 29, 2024
e81f617
It worked, so add the rest of the functions
pvillacorta Aug 29, 2024
15c33b2
Not export `reset_magnetization!`
pvillacorta Aug 29, 2024
c943212
Fix typo in docstring
pvillacorta Aug 29, 2024
0baf29c
Try to separate tests for core and motion (see Oceananigans.jl)
pvillacorta Aug 29, 2024
e29418c
Try to fix error on runtests.yml
pvillacorta Aug 29, 2024
911544f
Try to fix buildkite tests
pvillacorta Aug 29, 2024
e792aff
Change test group title for buildkite
pvillacorta Aug 29, 2024
007ee25
Try to interpolate env variable with $$
pvillacorta Aug 29, 2024
316fabf
Try with only one $
pvillacorta Aug 29, 2024
7049c60
Define env for each buildkite step
pvillacorta Aug 29, 2024
d88ecba
Motion and NoMotion tests separated for buildkite
pvillacorta Aug 29, 2024
9913be1
Only test `get_spin_coords` for ArbitraryAction in gpu
pvillacorta Aug 30, 2024
a156553
Fix test to use Float32
pvillacorta Aug 30, 2024
2655f0d
Disable benchmarks temporarily
pvillacorta Aug 30, 2024
44debdd
Only test ArbitraryMotion for oneAPI
pvillacorta Aug 30, 2024
67f2f33
New example phantoms
pvillacorta Aug 30, 2024
2a9aac7
Test ArbitraryMotion with all vendors again
pvillacorta Aug 30, 2024
d7ea6b7
Trying to find out where the error produces for oneAPI
pvillacorta Aug 30, 2024
42c21d2
Keep trying
pvillacorta Aug 30, 2024
0210669
Merge branch `new-motion-debug` into `new-motion`
pvillacorta Sep 3, 2024
fb7a740
Leave core tests as they were before debugging
pvillacorta Sep 3, 2024
51c71cc
`_ = sum(t)`
pvillacorta Sep 3, 2024
7d1ddc0
New function `_unit_time`
pvillacorta Sep 3, 2024
86a5760
Merge branch 'master' into new-motion
pvillacorta Sep 3, 2024
f0707aa
Squashed commit of the following:
pvillacorta Sep 12, 2024
586adcf
Uncomment informative messages
pvillacorta Sep 12, 2024
2177410
Change compat from julia 1.9 to 1.10
pvillacorta Sep 13, 2024
32cd42d
Requested changes
pvillacorta Sep 13, 2024
e5c9dd8
consts in upper case
pvillacorta Sep 15, 2024
0b1f31a
Fix and rename aux motion functions
pvillacorta Sep 15, 2024
717ee28
Add functor to Motion. MotionList cannot have a functor
pvillacorta Sep 15, 2024
d7666f6
Fix tests
pvillacorta Sep 15, 2024
ad10265
`cis` -> `_cis`
pvillacorta Sep 15, 2024
27ecbe5
Formatting and renaming
pvillacorta Sep 15, 2024
5e71f16
Back to `(cos.(ϕ) .+ im .* sin.(ϕ))`
pvillacorta Sep 15, 2024
b79a28b
Add `KomaMRIBase` into `sort_motions!` call
pvillacorta Sep 15, 2024
b4a878b
Add issue to Interpolations.jl
pvillacorta Sep 16, 2024
30cc9cc
`outflow_spin_reset!` inside all methods
pvillacorta Sep 17, 2024
12f6fed
Workgroup size back to 512
pvillacorta Sep 17, 2024
108886d
Remove `*`, since it produces errors in CPU
pvillacorta Sep 17, 2024
0430560
Suggested changes for flow functions
pvillacorta Sep 18, 2024
19d54e0
Suggested changes about `plot_phantom_map`
pvillacorta Sep 18, 2024
e7c4db2
Remove unnecessary `T` declaration
pvillacorta Sep 18, 2024
5780c31
Squashed commit of the following:
pvillacorta Sep 19, 2024
567e406
Add tests to new `plot_phantom_map` method
pvillacorta Sep 19, 2024
f2ad03b
Solve bug with `TimeRange` in the KomaMRIPlots tests
pvillacorta Sep 19, 2024
e416800
Suggested changes
pvillacorta Sep 19, 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
12 changes: 5 additions & 7 deletions KomaMRIBase/src/KomaMRIBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ include("datatypes/Phantom.jl")
include("datatypes/simulation/DiscreteSequence.jl")
include("timing/TimeStepCalculation.jl")
include("timing/TrapezoidalIntegration.jl")
include("timing/UnitTime.jl")

# Main
export γ # gyro-magnetic ratio [Hz/T]
Expand All @@ -47,12 +46,11 @@ export kfoldperm, trapz, cumtrapz
# Phantom
export brain_phantom2D, brain_phantom3D, pelvis_phantom2D, heart_phantom
# Motion
export MotionModel
export NoMotion, SimpleMotion, ArbitraryMotion
export SimpleMotionType
export Translation, Rotation, HeartBeat
export PeriodicTranslation, PeriodicRotation, PeriodicHeartBeat
export get_spin_coords
export AbstractMotion, Motion, MotionVector, NoMotion
export SimpleMotion, ArbitraryMotion
export Translation, Rotation, HeartBeat, Trajectory, FlowTrajectory
export TimeScale, TimeRange, Periodic
export sort_motions!, get_spin_coords
pvillacorta marked this conversation as resolved.
Show resolved Hide resolved
# Secondary
export get_kspace, rotx, roty, rotz
# Additionals
Expand Down
69 changes: 43 additions & 26 deletions KomaMRIBase/src/datatypes/Phantom.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
abstract type MotionModel{T<:Real} end

#Motion models:
include("phantom/motion/SimpleMotion.jl")
include("phantom/motion/ArbitraryMotion.jl")
include("phantom/motion/NoMotion.jl")
# TimeScale:
include("../timing/TimeScale.jl")
# Motion:
abstract type AbstractMotion{T<:Real} end
include("phantom/Motion.jl")
include("phantom/NoMotion.jl")

"""
obj = Phantom(name, x, y, z, ρ, T1, T2, T2s, Δw, Dλ1, Dλ2, Dθ, motion)
Expand Down Expand Up @@ -54,7 +54,7 @@
Dθ::AbstractVector{T} = zeros(eltype(x), size(x))
#Diff::Vector{DiffusionModel} #Diffusion map
#Motion
motion::MotionModel{T} = NoMotion{eltype(x)}()
motion::AbstractMotion{T} = NoMotion{eltype(x)}()
end

"""Size and length of a phantom"""
Expand All @@ -67,18 +67,29 @@
Base.getindex(x::Phantom, i::Integer) = x[i:i]

"""Compare two phantoms"""
Base.:(==)(obj1::Phantom, obj2::Phantom) = reduce(
&,
[getfield(obj1, field) == getfield(obj2, field) for field in Iterators.filter(x -> !(x == :name), fieldnames(Phantom))],
)
Base.:(≈)(obj1::Phantom, obj2::Phantom) = reduce(&, [getfield(obj1, field) ≈ getfield(obj2, field) for field in Iterators.filter(x -> !(x == :name), fieldnames(Phantom))])
Base.:(==)(m1::MotionModel, m2::MotionModel) = false
Base.:(≈)(m1::MotionModel, m2::MotionModel) = false
function Base.:(==)(obj1::Phantom, obj2::Phantom)
return reduce(
&,
[
getfield(obj1, field) == getfield(obj2, field) for
field in Iterators.filter(x -> !(x == :name), fieldnames(Phantom))
],
)
end
function Base.:(≈)(obj1::Phantom, obj2::Phantom)
return reduce(

Check warning on line 80 in KomaMRIBase/src/datatypes/Phantom.jl

View check run for this annotation

Codecov / codecov/patch

KomaMRIBase/src/datatypes/Phantom.jl#L79-L80

Added lines #L79 - L80 were not covered by tests
&,
[
getfield(obj1, field) ≈ getfield(obj2, field) for
field in Iterators.filter(x -> !(x == :name), fieldnames(Phantom))

Check warning on line 84 in KomaMRIBase/src/datatypes/Phantom.jl

View check run for this annotation

Codecov / codecov/patch

KomaMRIBase/src/datatypes/Phantom.jl#L84

Added line #L84 was not covered by tests
],
)
end

"""Separate object spins in a sub-group"""
Base.getindex(obj::Phantom, p::Union{AbstractRange,AbstractVector,Colon}) = begin
fields = []
for field in Iterators.filter(x -> !(x == :name), fieldnames(Phantom))
for field in Iterators.filter(x -> x != :name, fieldnames(Phantom))
push!(fields, (field, getfield(obj, field)[p]))
end
return Phantom(; name=obj.name, fields...)
Expand All @@ -87,21 +98,25 @@
"""Separate object spins in a sub-group (lightweigth)."""
Base.view(obj::Phantom, p::Union{AbstractRange,AbstractVector,Colon}) = begin
fields = []
for field in Iterators.filter(x -> !(x == :name), fieldnames(Phantom))
for field in Iterators.filter(x -> x != :name, fieldnames(Phantom))
push!(fields, (field, @view(getfield(obj, field)[p])))
end
return Phantom(; name=obj.name, fields...)
end

"""Addition of phantoms"""
+(obj1::Phantom, obj2::Phantom) = begin
Nmaxchars = 50
name = first(obj1.name * "+" * obj2.name, Nmaxchars)
pvillacorta marked this conversation as resolved.
Show resolved Hide resolved
fields = []
for field in Iterators.filter(x -> !(x == :name), fieldnames(Phantom))
for field in Iterators.filter(x -> x != :name, fieldnames(Phantom))
push!(fields, (field, [getfield(obj1, field); getfield(obj2, field)]))
end
Nmaxchars = 50
name = first(obj1.name * "+" * obj2.name, Nmaxchars)
return Phantom(; name=name, fields...)
return Phantom(;
name=name,
fields...,
motion=vcat(obj1.motion, obj2.motion, length(obj1), length(obj2))
)
end

"""Scalar multiplication of a phantom"""
Expand Down Expand Up @@ -177,16 +192,18 @@
Dλ1=Dλ1[ρ .!= 0],
Dλ2=Dλ2[ρ .!= 0],
Dθ=Dθ[ρ .!= 0],
motion=SimpleMotion(
PeriodicHeartBeat(;
period=period,
asymmetry=asymmetry,
motion=MotionVector(
HeartBeat(;
times=Periodic(; period=period, asymmetry=asymmetry),
circumferential_strain=circumferential_strain,
radial_strain=radial_strain,
longitudinal_strain=0.0,
),
PeriodicRotation(;
period=period, asymmetry=asymmetry, yaw=rotation_angle, pitch=0.0, roll=0.0
Rotation(;
times=Periodic(; period=period, asymmetry=asymmetry),
yaw=rotation_angle,
pitch=0.0,
roll=0.0,
),
),
)
Expand Down
120 changes: 120 additions & 0 deletions KomaMRIBase/src/datatypes/phantom/Motion.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
abstract type Motion{T<:Real} end

is_composable(m::Motion) = false

struct MotionVector{T<:Real} <: AbstractMotion{T}
motions::Vector{<:Motion{T}}
end

MotionVector(motions...) = length([motions]) > 0 ? MotionVector([motions...]) : @error "You must provide at least one motion as input argument. If you do not want to define motion, use `NoMotion{T}()`"

include("motion/SimpleMotion.jl")
include("motion/ArbitraryMotion.jl")

Base.getindex(mv::MotionVector, p::Union{AbstractRange, AbstractVector, Colon, Integer}) = MotionVector(getindex.(mv.motions, Ref(p)))
Base.view(mv::MotionVector, p::Union{AbstractRange, AbstractVector, Colon, Integer}) = MotionVector(view.(mv.motions, Ref(p)))

""" Addition of MotionVectors """
function Base.vcat(m1::MotionVector{T}, m2::MotionVector{T}, Ns1::Int, Ns2::Int) where {T<:Real}
mv1 = m1.motions
mv1_aux = Motion{T}[]
for i in 1:length(mv1)
if typeof(mv1[i]) <: ArbitraryMotion
zeros1 = similar(mv1[i].dx, Ns2, size(mv1[i].dx, 2))
zeros1 .= zero(T)
push!(mv1_aux, typeof(mv1[i])(mv1[i].times, [[getfield(mv1[i], d); zeros1] for d in filter(x -> x != :times, fieldnames(typeof(mv1[i])))]...))
else
push!(mv1_aux, mv1[i])

Check warning on line 27 in KomaMRIBase/src/datatypes/phantom/Motion.jl

View check run for this annotation

Codecov / codecov/patch

KomaMRIBase/src/datatypes/phantom/Motion.jl#L27

Added line #L27 was not covered by tests
end
end
mv2 = m2.motions
mv2_aux = Motion{T}[]
for i in 1:length(mv2)
if typeof(mv2[i]) <: ArbitraryMotion
zeros2 = similar(mv2[i].dx, Ns1, size(mv2[i].dx, 2))
zeros2 .= zero(T)
push!(mv2_aux, typeof(mv2[i])(mv2[i].times, [[zeros2; getfield(mv2[i], d)] for d in filter(x -> x != :times, fieldnames(typeof(mv2[i])))]...))
else
push!(mv2_aux, mv2[i])

Check warning on line 38 in KomaMRIBase/src/datatypes/phantom/Motion.jl

View check run for this annotation

Codecov / codecov/patch

KomaMRIBase/src/datatypes/phantom/Motion.jl#L38

Added line #L38 was not covered by tests
end
end
return MotionVector([mv1_aux; mv2_aux])
end

""" Compare two motion vectors """
function Base.:(==)(mv1::MotionVector{T}, mv2::MotionVector{T}) where {T<:Real}
sort_motions!(mv1)
sort_motions!(mv2)
return reduce(&, mv1.motions .== mv2.motions)
end
function Base.:(≈)(mv1::MotionVector{T}, mv2::MotionVector{T}) where {T<:Real}
sort_motions!(mv1)
sort_motions!(mv2)
return reduce(&, mv1.motions .≈ mv2.motions)

Check warning on line 53 in KomaMRIBase/src/datatypes/phantom/Motion.jl

View check run for this annotation

Codecov / codecov/patch

KomaMRIBase/src/datatypes/phantom/Motion.jl#L50-L53

Added lines #L50 - L53 were not covered by tests
end
pvillacorta marked this conversation as resolved.
Show resolved Hide resolved

"""
x, y, z = get_spin_coords(motion, x, y, z, t)

Calculates the position of each spin at a set of arbitrary time instants, i.e. the time steps of the simulation.
For each dimension (x, y, z), the output matrix has ``N_{\text{spins}}`` rows and `length(t)` columns.

# Arguments
- `motion`: (`::Vector{<:Motion{T<:Real}}`) phantom motion
- `x`: (`::AbstractVector{T<:Real}`, `[m]`) spin x-position vector
- `y`: (`::AbstractVector{T<:Real}`, `[m]`) spin y-position vector
- `z`: (`::AbstractVector{T<:Real}`, `[m]`) spin z-position vector
- `t`: (`::AbstractArray{T<:Real}`) horizontal array of time instants

# Returns
- `x, y, z`: (`::Tuple{AbstractArray, AbstractArray, AbstractArray}`) spin positions over time
"""
function get_spin_coords(
mv::MotionVector{T},
x::AbstractVector{T},
y::AbstractVector{T},
z::AbstractVector{T},
t::AbstractArray{T}
) where {T<:Real}
# Buffers for positions:
xt, yt, zt = x .+ 0*t, y .+ 0*t, z .+ 0*t
# Buffers for displacements:
ux, uy, uz = similar(xt), similar(yt), similar(zt)

# Composable motions: they need to be run sequentially
pvillacorta marked this conversation as resolved.
Show resolved Hide resolved
for m in Iterators.filter(is_composable, mv.motions)
displacement_x!(ux, m, xt, yt, zt, t)
displacement_y!(uy, m, xt, yt, zt, t)
displacement_z!(uz, m, xt, yt, zt, t)
xt .+= ux
yt .+= uy
zt .+= uz
end
# Additive motions: these motions can be run in parallel
for m in Iterators.filter(!is_composable, mv.motions)
displacement_x!(ux, m, x, y, z, t)
displacement_y!(uy, m, x, y, z, t)
displacement_z!(uz, m, x, y, z, t)
xt .+= ux
yt .+= uy
zt .+= uz
end
return xt, yt, zt
end

"""
times = times(motion)
"""
times(m::Motion) = times(m.times)
times(mv::MotionVector{T}) where {T<:Real} = begin
nodes = reduce(vcat, [times(m) for m in mv.motions]; init=[zero(T)])
return unique(sort(nodes))

Check warning on line 111 in KomaMRIBase/src/datatypes/phantom/Motion.jl

View check run for this annotation

Codecov / codecov/patch

KomaMRIBase/src/datatypes/phantom/Motion.jl#L109-L111

Added lines #L109 - L111 were not covered by tests
end

"""
sort_motions!
"""
function sort_motions!(mv::MotionVector{T}) where {T<:Real}
sort!(mv.motions; by=m -> times(m)[1])
return nothing
end
31 changes: 31 additions & 0 deletions KomaMRIBase/src/datatypes/phantom/NoMotion.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
struct NoMotion{T<:Real} <: AbstractMotion{T} end

Base.getindex(mv::NoMotion, p::Union{AbstractRange, AbstractVector, Colon, Integer}) = mv

Check warning on line 3 in KomaMRIBase/src/datatypes/phantom/NoMotion.jl

View check run for this annotation

Codecov / codecov/patch

KomaMRIBase/src/datatypes/phantom/NoMotion.jl#L3

Added line #L3 was not covered by tests
Base.view(mv::NoMotion, p::Union{AbstractRange, AbstractVector, Colon, Integer}) = mv

""" Addition of NoMotions """
Base.vcat(m1::NoMotion{T}, m2::AbstractMotion{T}, Ns1::Int, Ns2::Int) where {T<:Real} = m2
Base.vcat(m1::AbstractMotion{T}, m2::NoMotion{T}, Ns1::Int, Ns2::Int) where {T<:Real} = m1

Check warning on line 8 in KomaMRIBase/src/datatypes/phantom/NoMotion.jl

View check run for this annotation

Codecov / codecov/patch

KomaMRIBase/src/datatypes/phantom/NoMotion.jl#L7-L8

Added lines #L7 - L8 were not covered by tests

Base.:(==)(m1::NoMotion{T}, m2::NoMotion{T}) where {T<:Real} = true
Base.:(≈)(m1::NoMotion{T}, m2::NoMotion{T}) where {T<:Real} = true

Check warning on line 11 in KomaMRIBase/src/datatypes/phantom/NoMotion.jl

View check run for this annotation

Codecov / codecov/patch

KomaMRIBase/src/datatypes/phantom/NoMotion.jl#L11

Added line #L11 was not covered by tests

function get_spin_coords(
mv::NoMotion{T},
x::AbstractVector{T},
y::AbstractVector{T},
z::AbstractVector{T},
t::AbstractArray{T}
) where {T<:Real}
return x, y, z
end

"""
times = times(motion)
"""
times(mv::NoMotion{T}) where {T<:Real} = [zero(T)]

"""
sort_motions!
"""
sort_motions!(mv::NoMotion) = nothing
Loading
Loading