From ba0a832e667de11b1c2642139df119547cedaaa8 Mon Sep 17 00:00:00 2001 From: Michiel Cottaar <michiel.cottaar@ndcn.ox.ac.uk> Date: Mon, 12 Feb 2024 17:46:02 +0000 Subject: [PATCH] Remove old overlapping --- src/overlapping/abstract.jl | 194 ------------------ .../gradient_pulses/gradient_pulses.jl | 8 - .../gradient_readouts/full_cartesian.jl | 24 --- .../gradient_readouts/gradient_readouts.jl | 6 - .../gradient_readouts/single_lines.jl | 97 --------- src/overlapping/overlapping.jl | 12 -- 6 files changed, 341 deletions(-) delete mode 100644 src/overlapping/abstract.jl delete mode 100644 src/overlapping/gradient_pulses/gradient_pulses.jl delete mode 100644 src/overlapping/gradient_readouts/full_cartesian.jl delete mode 100644 src/overlapping/gradient_readouts/gradient_readouts.jl delete mode 100644 src/overlapping/gradient_readouts/single_lines.jl delete mode 100644 src/overlapping/overlapping.jl diff --git a/src/overlapping/abstract.jl b/src/overlapping/abstract.jl deleted file mode 100644 index e34bb6d..0000000 --- a/src/overlapping/abstract.jl +++ /dev/null @@ -1,194 +0,0 @@ -module Abstract - -import StaticArrays: SVector -import ...BuildingBlocks: BuildingBlock, ContainerBlock, RFPulseBlock, get_children_indices, VariableNotAvailable -import ...Wait: WaitBlock -import ...Readouts: InstantReadout -import ...Gradients: GradientBlock, split_gradient, ConstantGradientBlock, ChangingGradientBlock -import ...Variables: duration, start_time, qvec, bmat_gradient, gradient_strength, slew_rate, VariableType, effective_time, gradient_strength, slew_rate -import ...Variables: flip_angle, amplitude, phase, frequency, bandwidth, inverse_bandwidth, N_left, N_right, slice_thickness, all_variables_symbols - -""" -Parent type for any gradient waveform that might overlap with RF pulses and/or readouts. - -New waveforms should sub-type from this one. -At the very least they should implement: -- [`waveform_sequence`](@ref): return the subsequent [`GradientBlock`](@ref) and [`WaitBlock`](@ref) objects describing the gradient waveform. To get the wavform in a more useful format use [`waveform`](@ref). -- [`interruptions`](@ref): return a vector of all [`RFPulseBlock`](@ref) and [`InstantReadout`](@ref) with information on which part of the waveform they interrupt. -""" -abstract type AbstractOverlapping <: ContainerBlock end - -""" - SingleInterrupted(grad_like_block, interruptions) - -Represents a single part of the waveform within [`GenericOverlapping`](@ref). -""" -struct SingleInterrupted{T<:Union{WaitBlock, GradientBlock}} - block :: T - interruptions :: Vector{NamedTuple{(:index, :time, :block), Tuple{Int64, Float64, <:Union{RFPulseBlock, InstantReadout}}}} -end - -""" - waveform_sequence(overlapping) - -Returns the gradient waveform as a sequence of [`WaitBlock`](@ref), [`ChangingGradientBlock`](@ref), and [`ConstantGradientBlock`](@ref) objects. - -This should be implemented for any sub-type of [`AbstractOverlapping`](@ref). -""" -function waveform_sequence end - - -""" - waveform(overlapping) - -Returns the gradient waveform of a [`AbstractOverlapping`](@ref) as a sequence of control points. -Each control point is stored as a tuple with the time in ms and the gradient as a length-3 vector. -The gradient is linearly interpolated between these points (see [`waveform_sequence`](@ref)). -""" -function waveform(ao::AbstractOverlapping) - result = Tuple{VariableType, SVector{3, VariableType}}[(0, zero(SVector{3, Float64}))] - for block in waveform_sequence(ao) - new_time = result[end][1] + max(duration(block), 0) - prev_grad = result[end][2] - if block isa WaitBlock - @assert all(abs.(gradient_strength(block)) <= 1e-12) "$(typeof(ao)) inserts WaitBlock before the gradient is zero. This is probably caused by an improper implementation of this gradient waveform." - push!(result, (new_time, prev_grad)) - elseif block isa ConstantGradientBlock - @assert all(gradient_strength(block) .≈ prev_grad) "$(typeof(ao)) inserts ConstantGradientBlock that does not match previous gradient strength. This is probably caused by an improper implementation of this gradient waveform." - push!(result, (new_time, prev_grad)) - elseif block isa ChangingGradientBlock - @assert all(block.gradient_strength_start .≈ prev_grad) "$(typeof(ao)) inserts ChangingGradientBlock that does not match previous gradient strength. This is probably caused by an improper implementation of this gradient waveform." - push!(result, (new_time, prev_grad .+ slew_rate(block) .* duration(block))) - else - error("Unrecognised block type in gradient waveform: $(typeof(ao)).") - end - end - if duration(ao) > result[end][1] - push!(result, (duration(ao), zero(SVector{3, Float64}))) - end - return result -end - - -""" - interruptions(overlapping) - -Returns the interruptions as a sequence named tuples with 3 elements: -- `index`: which object in the [`waveform`](@ref) should be interrupted. -- `time`: time since the start of the [`waveform`](@ref) object that the interruptions takes place ([`effective_time`](@ref) for RF pulses). -- `object`: [`RFPulseBlock`](@ref) or [`InstantReadout`](@ref). - -This should be implemented for any sub-type of [`AbstractOverlapping`](@ref). -""" -function interruptions end - -duration(ao::AbstractOverlapping) = sum(duration.(waveform_sequence(ao))) -duration(single::SingleInterrupted) = duration(single.block) - -pulses(ao::AbstractOverlapping) = [pulse for (_, _, pulse) in interruptions(ao) if pulse isa RFPulseBlock] -readouts(ao::AbstractOverlapping) = [readout for (_, _, readout) in interruptions(ao) if readout isa InstantReadout] - -# For any overlapping building blocks with a single RF pulse, get information about that RF pulse. -for (func_symbol, _) in [Dict(all_variables_symbols)[:pulse]..., :effective_time => ""] - if func_symbol == :slice_thickness - continue - end - @eval function $func_symbol(ao::AbstractOverlapping, args...; kwargs...) - single_pulse = pulses(ao) - if iszero(length(single_pulse)) - throw(VariableNotAvailable(typeof(ao), $func_symbol)) - elseif length(single_pulse) > 1 - error("Building block has multipl pulses, so cannot compute ", $func_symbol, ".") - end - $func_symbol(single_pulse[1], args...; kwargs...) - end -end - -# Acting as a valid container -get_children_indices(ao::AbstractOverlapping) = 1:length(waveform_sequence(ao)) -function Base.getindex(ao::AbstractOverlapping, index::Integer) - grad_like_block = waveform_sequence(ao)[index] - inter = interruptions(ao) - first_interrupt = findfirst(int -> int[2] == index, inter) - if isnothing(first_interrupt) - return grad_like_block - else - last_interrupt = findlast(int -> int[2] == index, inter) - return SingleInterrupted(grad_like_block, inter[first_interrupt:last_interrupt]) - end -end - -start_time(ao::AbstractOverlapping, index::Integer) = sum(duration.(waveform_sequence(ao)[1:index])) - -function get_part(si::SingleInterrupted, first::Union{Nothing, Number}, last::Union{Nothing, Number}) - if isnothing(first) - if isnothing(last) - part = si.block - else - (part, _) = split_gradient(si, si.interruptions[last][1]) - end - else - tfirst = si.interruptions[first][1] - if isnothing(last) - (_, part) = split_gradient(si, tfirst) - else - (_, part, _) = split_gradient(si, tfirst, so.interruptions[last][1]) - end - end - return part -end - -function get_parts(ao::AbstractOverlapping, first::Union{Nothing, Integer}, last::Union{Nothing, Integer}) - inter = interruptions(ao) - form = waveform_sequence(ao) - whole_start_index = isnothing(first) ? 0 : inter[first].index - whole_final_index = isnothing(last) ? length(form) + 1 : inter[last].index - if whole_start_index == whole_final_index - return [split_gradient(form[whole_start_index], inter[first].time, inter[last].time)] - end - - parts = form[whole_start_index+1:whole_final_index-1] - if !isnothing(first) - pushfirst!(parts, split_gradient(form[whole_start_index], inter[first].time)[2]) - end - if !isnothing(last) - push!(parts, split_gradient(form[whole_final_index], inter[last].time)[1]) - end - return parts -end - - -""" - qvec(overlapping[, first_interruption, last_interruption]) - -Computes the area under the curve for the gradient waveform in [`AbstractOverlapping`](@ref). - -If `first_interruption` is set to something else than `nothing`, only the gradient waveform after this RF pulse/Readout will be considered. -Similarly, if `last_interruption` is set to something else than `nothing`, only the gradient waveform up to this RF pulse/Readout will be considered. -""" -function qvec(ao::AbstractOverlapping, index1::Union{Nothing, Integer}, index2::Union{Nothing, Integer}) - @assert isnothing(index1) || isnothing(index2) || index2 >= index1 - if (index1 isa Number) && (index1 == index2) - return zeros(3) - end - sum(qvec.(get_parts(ao, index1, index2)); init=zero(SVector{3, Float64})) -end -qvec(ao::AbstractOverlapping) = qvec(ao, nothing, nothing) - -function bmat_gradient(ao::AbstractOverlapping, qstart, index1::Union{Nothing, Integer}, index2::Union{Nothing, Integer}) - @assert isnothing(index1) || isnothing(index2) || index2 >= index1 - if (index1 isa Number) && (index1 == index2) - return zeros(3, 3) - end - result = Matrix{VariableType}(zeros(3, 3)) - qcurrent = Vector{VariableType}(qstart) - - for part in get_parts(ao, index1, index2) - result = result .+ bmat_gradient(part, qcurrent) - qcurrent = qcurrent .+ qvec(part, qcurrent) - end - return result -end -bmat_gradient(ao::AbstractOverlapping, qstart) = bmat_gradient(ao, qstart, nothing, nothing) - -end \ No newline at end of file diff --git a/src/overlapping/gradient_pulses/gradient_pulses.jl b/src/overlapping/gradient_pulses/gradient_pulses.jl deleted file mode 100644 index fcab143..0000000 --- a/src/overlapping/gradient_pulses/gradient_pulses.jl +++ /dev/null @@ -1,8 +0,0 @@ -module GradientPulses -include("trapezoid_gradients.jl") -include("spoilt_slice_selects.jl") - -import .TrapezoidGradients: TrapezoidGradient -import .SpoiltSliceSelects: SpoiltSliceSelect - -end \ No newline at end of file diff --git a/src/overlapping/gradient_readouts/full_cartesian.jl b/src/overlapping/gradient_readouts/full_cartesian.jl deleted file mode 100644 index ebb8277..0000000 --- a/src/overlapping/gradient_readouts/full_cartesian.jl +++ /dev/null @@ -1,24 +0,0 @@ -module Cartesian -import ....Variables: inverse_fov, resolution, inverse_voxel_size -import ...GradientPulses: TrapezoidGradient -import ..SingleLines: SingleLine - -""" - FullCartesianReadout(nlines_per_readout, nreadout, ) -""" -struct FullCartesianReadout - nlines_per_readout :: Int - nreadout :: Int - prepare :: TrapezoidGradient - positive_readout :: SingleLine - negative_readout :: SingleLine - blip :: TrapezoidGradient -end - -inverse_fov(fc::FullCartesianReadout) = [inverse_fov(fc.positive_readout), 1e3 * qvec(fc.blip)[2]] -resolution(fc::FullCartesianReadout) = [resolution(fc.positive_readout), fc.nlines_per_readout * fc.nreadout] -inverse_voxel_size(fc::FullCartesianReadout) = inverse_fov(fc) .* resolution(fc) - - - -end \ No newline at end of file diff --git a/src/overlapping/gradient_readouts/gradient_readouts.jl b/src/overlapping/gradient_readouts/gradient_readouts.jl deleted file mode 100644 index 4816ed2..0000000 --- a/src/overlapping/gradient_readouts/gradient_readouts.jl +++ /dev/null @@ -1,6 +0,0 @@ -module GradientReadouts - -include("single_lines.jl") - -import .SingleLines: SingleLine, opposite_kspace_lines -end \ No newline at end of file diff --git a/src/overlapping/gradient_readouts/single_lines.jl b/src/overlapping/gradient_readouts/single_lines.jl deleted file mode 100644 index eaed460..0000000 --- a/src/overlapping/gradient_readouts/single_lines.jl +++ /dev/null @@ -1,97 +0,0 @@ -module SingleLines -import JuMP: @constraint -import ....BuildingBlocks: set_simple_constraints! -import ....BuildSequences: global_model -import ....Readouts: ADC -import ....Variables: dwell_time, inverse_fov, resolution, nsamples, effective_time, gradient_strength, slew_rate, inverse_voxel_size, rise_time, duration, variables, fov, voxel_size, flat_time, ramp_overlap, VariableType, get_free_variable -import ...Abstract: AbstractOverlapping, waveform_sequence, interruptions -import ...GradientPulses: TrapezoidGradient - -struct SingleLine <: AbstractOverlapping - adc :: ADC - grad :: TrapezoidGradient - ramp_overlap :: VariableType -end - -""" - SingleLine(rotate=:FOV, orientation=[1, 0, 0], ramp_overlap=1., variables...) - -Overlays a [`TrapezoidGradient`](@ref) and [`ADC`](@ref) event. - -## Parameters -- `rotate`: with which user-set parameter will this gradient be rotated (default: :FOV). -- `orientation`: gradient orientation before rotation (default: [1, 0, 0]). -- `ramp_overlap`: how much the gradient ramp should overlap with the ADC. 0 for no overlap, 1 for full overlap (default: 1). Can be set to `nothing` to become a free variable. - -## Variables -New variables added at this level: -- [`fov`](@ref): FOV of the output image along this single k-space line in mm. -- [`voxel_size`](@ref): size of each voxel along this single k-space line in mm. - -ADC variables: -- [`resolution`](@ref): number of voxels in the readout direction. This can be a non-integer value during optimisation. -- [`nsamples`](@ref): number of samples in the readout. This can be a non-integer value during optimisation. -- [`dwell_time`](@ref): Time between each readout sample in ms. -- [`effective_time`](@ref): time till the center of k-space from the start of the gradient (might not be the same as the start of the ADC). - -Gradient variables: -- [`gradient_strength`](@ref): Maximum gradient strength achieved during the pulse in kHz/um -""" -function SingleLine(; rotate=:FOV, orientation=[1, 0, 0], ramp_overlap=1., resolution=nothing, oversample=nothing, nsamples=nothing, dwell_time=nothing, kwargs...) - res = SingleLine( - ADC(; resolution=resolution, oversample=oversample, nsamples=nsamples, dwell_time=dwell_time), - TrapezoidGradient(orientation=orientation, duration=:min, rotate=rotate), - get_free_variable(ramp_overlap), - ) - @constraint global_model() (res.ramp_overlap * rise_time(res.grad) * 2 + flat_time(res.grad)) == duration(res.adc) - set_simple_constraints!(res, kwargs) - return res -end - -waveform_sequence(sl::SingleLine) = waveform_sequence(sl.grad) -interruptions(sl::SingleLine) = [(index=2, time=effective_time(sl.adc) - rise_time(sl.grad), object=sl.adc)] - -ramp_overlap(sl::SingleLine) = sl.ramp_overlap -effective_time(sl::SingleLine) = (1. - ramp_overlap(sl)) * rise_time(sl.grad) + effective_time(sl.adc) -dwell_time(sl::SingleLine) = dwell_time(sl.adc) -slew_rate(sl::SingleLine) = slew_rate(sl.grad)[1] -gradient_strenth(sl::SingleLine) = slew_rate(sl) * rise_time(sl.grad) -inverse_fov(sl::SingleLine) = 1e3 * dwell_time(sl) * gradient_strenth(sl) -inverse_voxel_size(sl::SingleLine) = 1e3 * duration(sl.adc) * gradient_strenth(sl) -nsamples(sl::SingleLine) = nsamples(sl.adc) -resolution(sl::SingleLine) = resolution(sl.adc) -duration(sl::SingleLine) = duration(sl.grad) - - -""" - opposite_kspace_lines(rotate=:FOV, orientation=[1, 0, 0], ramp_overlap=1., variables...) - -Create two [`SingleLine`](@ref) objects that run in the opposite direction through k-space. - -The first will run in the `+orientation` direction, the other in the `-orienation` direction. - -Parameters and variables are the same as for [`SingleLine`](@ref). -""" -function opposite_kspace_lines(; kwargs...) - positive_line = SingleLine(; kwargs...) - grad = positive_line.grad - negative_grad = TrapezoidGradient( - grad.rise_time, - grad.flat_time, - -grad.slew_rate, - grad.rotate, - grad.scale, - grad.time_before_pulse, - grad.pulse, - grad.time_after_pulse, - grad.slew_rate_1d - ) - negative_line = SingleLine( - positive_line.adc, - negative_grad, - positive_line.ramp_overlap - ) - return (positive_line, negative_line) -end - -end \ No newline at end of file diff --git a/src/overlapping/overlapping.jl b/src/overlapping/overlapping.jl deleted file mode 100644 index 77a039e..0000000 --- a/src/overlapping/overlapping.jl +++ /dev/null @@ -1,12 +0,0 @@ -module Overlapping -include("abstract.jl") -include("generic.jl") -include("gradient_pulses/gradient_pulses.jl") -include("gradient_readouts/gradient_readouts.jl") - -import .Abstract: AbstractOverlapping, interruptions, waveform, get_parts, waveform_sequence -import .Generic: GenericOverlapping -import .GradientPulses: TrapezoidGradient, SpoiltSliceSelect -import .GradientReadouts: SingleLine, opposite_kspace_lines - -end \ No newline at end of file -- GitLab