From d3fb2bb6279331ef988209998a515e979031268e Mon Sep 17 00:00:00 2001
From: Michiel Cottaar <michiel.cottaar@ndcn.ox.ac.uk>
Date: Fri, 2 Feb 2024 17:45:30 +0000
Subject: [PATCH] Add object for single line of k-space

---
 src/MRIBuilder.jl                             |  4 +-
 .../gradient_pulses/trapezoid_gradients.jl    |  4 +-
 .../gradient_readouts/gradient_readouts.jl    |  6 +++
 .../gradient_readouts/single_lines.jl         | 38 +++++++++++++++++++
 src/overlapping/overlapping.jl                |  4 +-
 src/readouts/ADCs.jl                          |  7 ++--
 src/variables.jl                              |  4 ++
 7 files changed, 60 insertions(+), 7 deletions(-)
 create mode 100644 src/overlapping/gradient_readouts/gradient_readouts.jl
 create mode 100644 src/overlapping/gradient_readouts/single_lines.jl

diff --git a/src/MRIBuilder.jl b/src/MRIBuilder.jl
index 0008f1f..8523111 100644
--- a/src/MRIBuilder.jl
+++ b/src/MRIBuilder.jl
@@ -40,8 +40,8 @@ export InstantGradientBlock
 import .Readouts: InstantReadout, ADC
 export InstantReadout, ADC
 
-import .Overlapping: TrapezoidGradient, SpoiltSliceSelect, interruptions, waveform
-export TrapezoidGradient, SpoiltSliceSelect, interruptions, waveform
+import .Overlapping: TrapezoidGradient, SpoiltSliceSelect, interruptions, waveform, SingleLine
+export TrapezoidGradient, SpoiltSliceSelect, interruptions, waveform, SingleLine
 
 import .Sequences: Sequence
 export Sequence
diff --git a/src/overlapping/gradient_pulses/trapezoid_gradients.jl b/src/overlapping/gradient_pulses/trapezoid_gradients.jl
index 705eeeb..0182510 100644
--- a/src/overlapping/gradient_pulses/trapezoid_gradients.jl
+++ b/src/overlapping/gradient_pulses/trapezoid_gradients.jl
@@ -50,6 +50,7 @@ struct TrapezoidGradient <: AbstractOverlapping
     time_before_pulse :: VariableType
     pulse :: Union{Nothing, RFPulseBlock}
     time_after_pulse :: VariableType
+    slew_rate_1d :: Union{Nothing, VariableType}
 end
 
 function TrapezoidGradient(; orientation=nothing, rise_time=nothing, flat_time=nothing, rotate=nothing, scale=nothing, pulse=nothing,kwargs...)
@@ -102,7 +103,8 @@ function TrapezoidGradient(; orientation=nothing, rise_time=nothing, flat_time=n
         scale,
         time_before_pulse,
         pulse,
-        time_after_pulse
+        time_after_pulse,
+        rate_1d
     )
 
     set_simple_constraints!(res, kwargs)
diff --git a/src/overlapping/gradient_readouts/gradient_readouts.jl b/src/overlapping/gradient_readouts/gradient_readouts.jl
new file mode 100644
index 0000000..d77f58e
--- /dev/null
+++ b/src/overlapping/gradient_readouts/gradient_readouts.jl
@@ -0,0 +1,6 @@
+module GradientReadouts
+
+include("single_lines.jl")
+
+import .SingleLines: SingleLine
+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
new file mode 100644
index 0000000..736a0e4
--- /dev/null
+++ b/src/overlapping/gradient_readouts/single_lines.jl
@@ -0,0 +1,38 @@
+module SingleLines
+import ....BuildingBlocks: set_simple_constraints!
+import ....Readouts: ADC
+import ....Variables: dwell_time, fov, resolution, nsamples, effective_time, gradient_strength, slew_rate, voxel_size, rise_time, duration, variables
+import ...Abstract: AbstractOverlapping, waveform, interruptions
+import ...GradientPulses: TrapezoidGradient
+
+struct SingleLine <: AbstractOverlapping
+    adc :: ADC
+    grad :: TrapezoidGradient
+end
+
+function SingleLine(; nsamples=nothing, dwell_time=nothing, time_to_center=nothing, adc_duration=nothing, center_halfway=true, kwargs...)
+    readout = ADC(nsamples=nsamples, dwell_time=dwell_time, time_to_center=time_to_center, duration=adc_duration, center_halfway=center_halfway)
+    res = SingleLine(
+        readout,
+        TrapezoidGradient(orientation=[1, 0, 0], rotate=:FOV, flat_time=duration(readout), duration=:min)
+    )
+    set_simple_constraints!(res, kwargs)
+    return res
+end
+
+waveform(sl::SingleLine) = waveform(sl.grad)
+interruptions(sl::SingleLine) = [(index=2, time=effective_time(sl.adc), object=sl.adc)]
+
+effective_time(sl::SingleLine) = rise_time(sl.grad) + effective_time(sl.adc)
+dwell_time(sl::SingleLine) = sl.adc.dwell_time
+slew_rate(sl::SingleLine) = sl.grad.slew_rate_1d
+gradient_strenth(sl::SingleLine) = slew_rate(sl) * rise_time(sl.grad)
+fov_inverse(sl::SingleLine) = 1e3 * dwell_time(sl) * gradient_strenth(sl)
+voxel_size_inverse(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)
+
+variables(::Type{<:SingleLine}) = [dwell_time, gradient_strenth, fov_inverse, voxel_size_inverse, resolution, duration]
+
+end
\ No newline at end of file
diff --git a/src/overlapping/overlapping.jl b/src/overlapping/overlapping.jl
index 3b5a7be..eda9b47 100644
--- a/src/overlapping/overlapping.jl
+++ b/src/overlapping/overlapping.jl
@@ -1,10 +1,12 @@
 module Overlapping
 include("abstract.jl")
 include("generic.jl")
-include("gradient_pulses//gradient_pulses.jl")
+include("gradient_pulses/gradient_pulses.jl")
+include("gradient_readouts/gradient_readouts.jl")
 
 import .Abstract: AbstractOverlapping, interruptions, waveform
 import .Generic: GenericOverlapping
 import .GradientPulses: TrapezoidGradient, SpoiltSliceSelect
+import .GradientReadouts: SingleLine
 
 end
\ No newline at end of file
diff --git a/src/readouts/ADCs.jl b/src/readouts/ADCs.jl
index 3e265d7..b8f924e 100644
--- a/src/readouts/ADCs.jl
+++ b/src/readouts/ADCs.jl
@@ -1,6 +1,6 @@
 module ADCs
 import JuMP: @constraint
-import ...Variables: variables, dwell_time, duration, effective_time, get_free_variable, VariableType, nsamples
+import ...Variables: variables, dwell_time, duration, effective_time, get_free_variable, VariableType, nsamples, resolution
 import ...BuildingBlocks: BuildingBlock, apply_simple_constraint!, set_simple_constraints!, fixed
 import ...BuildSequences: global_model
 
@@ -24,7 +24,7 @@ struct ADC <: BuildingBlock
     time_to_center :: VariableType
 end
 
-function ADC(nsamples=nothing, dwell_time=nothing, time_to_center=nothing, center_halfway=true, kwargs...)
+function ADC(; nsamples=nothing, dwell_time=nothing, time_to_center=nothing, center_halfway=true, kwargs...)
     res = ADC(
         get_free_variable(nsamples),
         get_free_variable(dwell_time),
@@ -46,8 +46,9 @@ dwell_time(adc::ADC) = adc.dwell_time
 duration(adc::ADC) = nsamples(adc) * dwell_time(adc)
 time_to_center(adc::ADC) = adc.time_to_center
 effective_time(adc::ADC) = time_to_center(adc)
+resolution(adc::ADC) = adc.nsamples
 
-variables(::Type{<:ADC}) = [nsamples, dwell_time, duration, time_to_center]
+variables(::Type{<:ADC}) = [nsamples, dwell_time, duration, time_to_center, resolution]
 
 function fixed(adc::ADC)
     # round nsamples during fixing
diff --git a/src/variables.jl b/src/variables.jl
index 7e94e0d..3c892b6 100644
--- a/src/variables.jl
+++ b/src/variables.jl
@@ -36,6 +36,10 @@ all_variables_symbols = [
     ],
     :readout => [
         :dwell_time => "Time between two samples in an `ADC` in ms.",
+        :nsamples => "Number of samples during a readout. During the optimisation this might produce non-integer values (also see [`resolution`](@ref)).",
+        :fov => "Size of the field of view in mm.",
+        :voxel_size => "Size of each voxel in mm.",
+        :resolution => "Number of voxels in the final readout (also see [`nsamples`](@ref)).",
     ]
 ]
 
-- 
GitLab