From 197d83dd5e5b5cd01bd9bd1c2aa229964b64d2f1 Mon Sep 17 00:00:00 2001
From: Michiel Cottaar <michiel.cottaar@ndcn.ox.ac.uk>
Date: Mon, 26 Feb 2024 16:04:50 +0000
Subject: [PATCH] Compute edge and start time

---
 src/MRIBuilder.jl                          |  4 +--
 src/components/readouts/ADCs.jl            |  1 +
 src/components/readouts/readouts.jl        |  2 +-
 src/components/readouts/single_readouts.jl |  3 ++-
 src/containers/abstract.jl                 | 21 +++++++++++++++
 src/containers/base_sequences.jl           | 20 +++++++++++++-
 src/containers/building_blocks.jl          | 31 ++++++++++++++++++----
 src/containers/containers.jl               |  2 +-
 8 files changed, 73 insertions(+), 11 deletions(-)

diff --git a/src/MRIBuilder.jl b/src/MRIBuilder.jl
index 59326aa..2905d98 100644
--- a/src/MRIBuilder.jl
+++ b/src/MRIBuilder.jl
@@ -26,8 +26,8 @@ export variables, duration, effective_time, flip_angle, amplitude, phase, freque
 import .Components: InstantPulse, ConstantPulse, SincPulse, GenericPulse, InstantGradient, SingleReadout, ADC
 export InstantPulse, ConstantPulse, SincPulse, GenericPulse, InstantGradient, SingleReadout, ADC
 
-import .Containers: ContainerBlock, start_time, end_time, waveform, waveform_sequence, events, BaseBuildingBlock, BuildingBlock, Wait, BaseSequence, nrepeat, Sequence, AlternativeBlocks, match_blocks!, get_index_single_TR
-export ContainerBlock, start_time, end_time, waveform, waveform_sequence, events, BaseBuildingBlock, BuildingBlock, Wait, BaseSequence, nrepeat, Sequence, AlternativeBlocks, match_blocks!, get_index_single_TR
+import .Containers: ContainerBlock, start_time, end_time, waveform, waveform_sequence, events, BaseBuildingBlock, BuildingBlock, Wait, BaseSequence, nrepeat, Sequence, AlternativeBlocks, match_blocks!, get_index_single_TR, readout_times, edge_times
+export ContainerBlock, start_time, end_time, waveform, waveform_sequence, events, BaseBuildingBlock, BuildingBlock, Wait, BaseSequence, nrepeat, Sequence, AlternativeBlocks, match_blocks!, get_index_single_TR, readout_times, edge_times
 
 import .Pathways: Pathway, duration_transverse, duration_dephase, bval, bmat, get_pathway
 export Pathway, duration_transverse, duration_dephase, bval, bmat, get_pathway
diff --git a/src/components/readouts/ADCs.jl b/src/components/readouts/ADCs.jl
index b4a6b7e..ca5792f 100644
--- a/src/components/readouts/ADCs.jl
+++ b/src/components/readouts/ADCs.jl
@@ -48,6 +48,7 @@ function ADC(; resolution=nothing, dwell_time=nothing, time_to_center=nothing, c
     return res
 end
 
+readout_times(adc::ADC) = range(0, duration(adc), Int(nsamples(adc)))
 oversample(adc::ADC) = adc.oversample
 nsamples(adc::ADC) = resolution(adc) * oversample(adc)
 dwell_time(adc::ADC) = adc.dwell_time
diff --git a/src/components/readouts/readouts.jl b/src/components/readouts/readouts.jl
index b28a9cd..0b6ec5d 100644
--- a/src/components/readouts/readouts.jl
+++ b/src/components/readouts/readouts.jl
@@ -3,6 +3,6 @@ include("ADCs.jl")
 include("single_readouts.jl")
 
 import ..AbstractTypes: ReadoutComponent
-import .ADCs: ADC
+import .ADCs: ADC, readout_times
 import .SingleReadouts: SingleReadout
 end
\ No newline at end of file
diff --git a/src/components/readouts/single_readouts.jl b/src/components/readouts/single_readouts.jl
index c814763..dfaf8fc 100644
--- a/src/components/readouts/single_readouts.jl
+++ b/src/components/readouts/single_readouts.jl
@@ -2,7 +2,7 @@ module SingleReadouts
 import JuMP: @constraint
 import ...AbstractTypes: ReadoutComponent
 import ....Variables: duration, effective_time, make_generic
-import ..ADCs: ADC
+import ..ADCs: ADC, readout_times
 
 """
     SingleReadout()
@@ -28,6 +28,7 @@ end
 
 duration(::SingleReadout) = 0.
 effective_time(::SingleReadout) = 0.
+readout_times(::SingleReadout) = [0.]
 
 make_generic(::SingleReadout) = ADC(1, 0., 0., 0.)
 end
\ No newline at end of file
diff --git a/src/containers/abstract.jl b/src/containers/abstract.jl
index 669ff1b..8cb582a 100644
--- a/src/containers/abstract.jl
+++ b/src/containers/abstract.jl
@@ -1,5 +1,6 @@
 module Abstract
 import ...Variables: AbstractBlock, duration, effective_time
+import ...Components.Readouts: readout_times
 
 """
 Parent type for `BuildingBlock` or `BaseSequence`, i.e., any building block that contains other MRI components/blocks.
@@ -43,5 +44,25 @@ Also see [`duration`](@ref), [`start_time`](@ref), and [`end_time`](@ref)
 effective_time(container::ContainerBlock, index, indices...) = start_time(container, index) + effective_time(container[index], indices...)
 
 
+"""
+    readout_times(sequence/ADC)
+
+Return the times of all of the readout events in ms.
+"""
+function readout_times end
+
+"""
+    edge_times(container)
+
+Returns all the edge times during a sequence in ms.
+
+Edges are defined as any time, when:
+- the edge of a building block
+- the slope of the gradient profile changes suddenly
+- an RF pulse starts or ends
+"""
+function edge_times end
+
+
 
 end
\ No newline at end of file
diff --git a/src/containers/base_sequences.jl b/src/containers/base_sequences.jl
index 0302288..281580d 100644
--- a/src/containers/base_sequences.jl
+++ b/src/containers/base_sequences.jl
@@ -7,7 +7,7 @@ import JuMP: @constraint
 import ...Variables: get_free_variable, repetition_time, VariableType, duration, variables, VariableNotAvailable, Variables, set_simple_constraints!, TR, make_generic
 import ...BuildSequences: global_model
 import ...Components: EventComponent
-import ..Abstract: ContainerBlock, start_time
+import ..Abstract: ContainerBlock, start_time, readout_times, edge_times
 import ..BuildingBlocks: Wait, BuildingBlock, BaseBuildingBlock
 
 """
@@ -83,6 +83,22 @@ repetition_time(bs::BaseSequence) = duration(bs)
 duration(bs::BaseSequence{0}) = 0.
 duration(bs::BaseSequence) = sum(duration.(bs); init=0.)
 
+function readout_times(seq::BaseSequence)
+    res = Float64[]
+    for (index, block) in enumerate(seq)
+        append!(res, readout_times(block) .+ start_time(seq, index))
+    end
+    return res
+end
+
+function edge_times(seq::BaseSequence)
+    res = Float64[]
+    for (index, block) in enumerate(seq)
+        append!(res, edge_times(block) .+ start_time(seq, index))
+    end
+    return unique(res)
+end
+
 """
     Sequence(blocks; name=:Sequence, variables...)
     Sequence(blocks...; name=:Sequence, variables...)
@@ -153,4 +169,6 @@ function make_generic(seq::BaseSequence)
     return Sequence(blocks)
 end
 
+
+
 end
diff --git a/src/containers/building_blocks.jl b/src/containers/building_blocks.jl
index 2856f2f..7fe8d03 100644
--- a/src/containers/building_blocks.jl
+++ b/src/containers/building_blocks.jl
@@ -5,9 +5,9 @@ module BuildingBlocks
 import LinearAlgebra: norm
 import JuMP: @constraint
 import StaticArrays: SVector
-import ..Abstract: ContainerBlock, start_time
+import ..Abstract: ContainerBlock, start_time, readout_times, edge_times, end_time
 import ...BuildSequences: global_model
-import ...Components: BaseComponent, GradientWaveform, EventComponent, NoGradient, ChangingGradient, ConstantGradient, split_gradient, DelayedEvent, RFPulseComponent, ReadoutComponent
+import ...Components: BaseComponent, GradientWaveform, EventComponent, NoGradient, ChangingGradient, ConstantGradient, split_gradient, DelayedEvent, RFPulseComponent, ReadoutComponent, InstantGradient
 import ...Variables: qval, bmat_gradient, effective_time, get_free_variable, qval3, slew_rate, gradient_strength
 import ...Variables: VariableType, duration, make_generic, get_pulse, get_readout, scanner_constraints!
 
@@ -112,14 +112,12 @@ equal_key(i1, i2) = i1 == i2
 
 function start_time(building_block::BaseBuildingBlock, index)
     time = 0.
-    prev_time = 0.
     for key in keys(building_block)
         if equal_key(key, index)
-            return prev_time
+            return time
         end
         component = building_block[key]
         if component isa GradientWaveform
-            prev_time = time
             time += duration(component)
         end
     end
@@ -206,6 +204,29 @@ function bmat_gradient(bb::BaseBuildingBlock, qstart, index1, index2)
 end
 bmat_gradient(bb::BaseBuildingBlock, qstart) = bmat_gradient(bb, qstart, nothing, nothing)
 
+function readout_times(bb::BaseBuildingBlock)
+    res = Float64[]
+    for (key, event) in events(bb)
+        if event isa ReadoutComponent
+            append!(res, readout_times(event) .+ start_time(bb, key))
+        end
+    end
+    return res
+end
+
+function edge_times(bb::BaseBuildingBlock)
+    res = Float64[]
+    for key in keys(bb)
+        object = bb[key]
+        if object isa Union{GradientWaveform, RFPulseComponent, InstantGradient}
+            @show key start_time(bb, key) end_time(bb, key)
+            push!(res, start_time(bb, key))
+            push!(res, end_time(bb, key))
+        end
+    end
+    return sort(unique(res))
+end
+
 """
     BuildingBlock(waveform, events; duration=nothing, orientation=nothing, group)
 
diff --git a/src/containers/containers.jl b/src/containers/containers.jl
index f2df3a1..4bd983b 100644
--- a/src/containers/containers.jl
+++ b/src/containers/containers.jl
@@ -4,7 +4,7 @@ include("building_blocks.jl")
 include("base_sequences.jl")
 include("alternatives.jl")
 
-import .Abstract: ContainerBlock, start_time, end_time, effective_time
+import .Abstract: ContainerBlock, start_time, end_time, effective_time, readout_times, edge_times
 import .BuildingBlocks: BaseBuildingBlock, BuildingBlock, Wait, waveform, waveform_sequence, events, ndim_grad
 import .BaseSequences: BaseSequence, Sequence, nrepeat, get_index_single_TR
 import .Alternatives: AlternativeBlocks, match_blocks!
-- 
GitLab