Skip to content
Snippets Groups Projects
Verified Commit 92d4820f authored by Michiel Cottaar's avatar Michiel Cottaar
Browse files

Generated multiple sequences in adjust

parent be9073d5
No related branches found
No related tags found
No related merge requests found
...@@ -10,7 +10,7 @@ import ..Containers: ContainerBlock, Sequence, Wait ...@@ -10,7 +10,7 @@ import ..Containers: ContainerBlock, Sequence, Wait
""" """
adjust(block; kwargs...) adjust(block; kwargs...)
Generate a new sequence/building_block/component with some post-fitting adjustments. Generate one or more new sequences/building_blocks/components with some post-fitting adjustments.
The following adjustments are allowed: The following adjustments are allowed:
- for MR gradients - for MR gradients
...@@ -21,6 +21,11 @@ The following adjustments are allowed: ...@@ -21,6 +21,11 @@ The following adjustments are allowed:
- `frequency`: shift the off-resonance frequency by the given value (in kHz). - `frequency`: shift the off-resonance frequency by the given value (in kHz).
- `scale`: multiply the RF pulse amplitude by the given value (used to model the B1 transmit field). - `scale`: multiply the RF pulse amplitude by the given value (used to model the B1 transmit field).
A vector of multiple values can be passed on to any of these in order to create multiple sequences with different adjustments.
The will usually be merged together. You can get the individual sequences by passing on `merge=false`.
The time between these repeated sequences can be adjusted using the keywords described in [`merge_sequences`](@ref) passed on to the merge keyword:
e.g., `merge=(wait_time=10, )` adds a wait time of 10 ms between each repeated sequence.
Specific sequence components that can be adjusted are identified by their `group` name. Specific sequence components that can be adjusted are identified by their `group` name.
For example, `adjust(sequence, dwi=(orientation=[0, 1, 0], ))` will set any gradient in the group `dwi` to point in the y-direction. For example, `adjust(sequence, dwi=(orientation=[0, 1, 0], ))` will set any gradient in the group `dwi` to point in the y-direction.
...@@ -28,9 +33,20 @@ To affect all gradients or pulses, use `gradient=` or `pulse`, e.g. ...@@ -28,9 +33,20 @@ To affect all gradients or pulses, use `gradient=` or `pulse`, e.g.
`adjust(sequence, pulse=(scale=0.5, ))` `adjust(sequence, pulse=(scale=0.5, ))`
will divide the amplitude of all RV pulses by two. will divide the amplitude of all RV pulses by two.
""" """
function adjust(block::AbstractBlock; kwargs...) function adjust(block::AbstractBlock; merge=true, kwargs...)
used_names = Set{Symbol}() used_names = Set{Symbol}()
res = adjust_helper(block, used_names; kwargs...) n_adjust, kwargs_list = adjust_kwargs_list(; kwargs...)
if isnothing(n_adjust)
res = adjust_helper(block, used_names; kwargs_list[1]...)
else
res = [adjust_helper(block, used_names; kw...) for kw in kwargs_list]
if merge !== false
if merge === true
merge = NamedTuple()
end
res = merge_sequences(res...; merge...)
end
end
unused_names = filter(keys(kwargs)) do key unused_names = filter(keys(kwargs)) do key
!(key in used_names) !(key in used_names)
end end
...@@ -40,6 +56,41 @@ function adjust(block::AbstractBlock; kwargs...) ...@@ -40,6 +56,41 @@ function adjust(block::AbstractBlock; kwargs...)
res res
end end
function adjust_kwargs_list(; kwargs...)
n_adjust = nothing
for (_, named_tuple) in kwargs
for key in keys(named_tuple)
value = named_tuple[key]
if key == :orientation && value isa AbstractVector{<:Number}
continue
end
if value isa AbstractVector
if isnothing(n_adjust)
n_adjust = length(value)
else
@assert length(value) == n_adjust
end
end
end
end
use_n_adjust = isnothing(n_adjust) ? 1 : n_adjust
kwargs_list = [Dict{Symbol, Any}([field=>Dict{Symbol, Any}() for field in keys(kwargs)]...) for _ in 1:use_n_adjust]
for (field, named_tuple) in kwargs
for key in keys(named_tuple)
value = named_tuple[key]
for index in 1:use_n_adjust
if (key == :orientation && value isa AbstractVector{<:Number}) || !(value isa AbstractVector)
kwargs_list[index][field][key] = value
else
kwargs_list[index][field][key] = value[index]
end
end
end
end
return (n_adjust, kwargs_list)
end
function adjust_helper(block::AbstractBlock, used_names::Set{Symbol}; gradient=(), pulse=(), kwargs...) function adjust_helper(block::AbstractBlock, used_names::Set{Symbol}; gradient=(), pulse=(), kwargs...)
params = [] params = []
adjust_type = adjustable(block) adjust_type = adjustable(block)
......
...@@ -29,11 +29,27 @@ ...@@ -29,11 +29,27 @@
new_dwi = adjust(dwi, DWI=(scale=0.5, orientation=[0., 1., 0.])) new_dwi = adjust(dwi, DWI=(scale=0.5, orientation=[0., 1., 0.]))
@test bval(new_dwi) 0.25 @test bval(new_dwi) 0.25
@test all(qval3(new_dwi[:gradient]) . [0., qval_orig/2, 0.]) @test all(qval3(new_dwi[:gradient]) . [0., qval_orig/2, 0.])
@testset "multiple adjustments" begin
new_dwi = adjust(dwi, DWI=(scale=[0.5, 1.], orientation=[0., 1., 0.]), merge=false)
@test length(new_dwi) == 2
@test bval(new_dwi[1]) 0.25
@test bval(new_dwi[2]) 1.
@test all(qval3(new_dwi[1][:gradient]) . [0., qval_orig/2, 0.])
@test all(qval3(new_dwi[2][:gradient]) . [0., qval_orig, 0.])
new_dwi = adjust(dwi, DWI=(scale=[0.5, 1.], orientation=[0., 1., 0.]))
@test duration(new_dwi) 160
new_dwi = adjust(dwi, DWI=(scale=[0.5, 1.], orientation=[0., 1., 0.]), merge=(wait_time=10, ))
@test duration(new_dwi) 170
end
end end
@testset "Rotate gradient" begin @testset "Rotate gradient" begin
new_dwi = adjust(dwi, gradient=(rotation=RotationVec(0., 0., π/4), )) new_dwi = adjust(dwi, gradient=(rotation=RotationVec(0., 0., π/4), ))
@test bval(new_dwi) 1. @test bval(new_dwi) 1.
@test all(qval3(new_dwi[:gradient]) . [qval_orig/√2, qval_orig/√2, 0.]) @test all(qval3(new_dwi[:gradient]) . [qval_orig/√2, qval_orig/√2, 0.])
end end
end end
end end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment