Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
MRIBuilder.jl
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Michiel Cottaar
MRIBuilder.jl
Commits
dc198ade
Verified
Commit
dc198ade
authored
1 year ago
by
Michiel Cottaar
Browse files
Options
Downloads
Patches
Plain Diff
Add generic waveforms
parent
d3194e83
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
src/waveforms/generic.jl
+172
-0
172 additions, 0 deletions
src/waveforms/generic.jl
src/waveforms/waveforms.jl
+4
-0
4 additions, 0 deletions
src/waveforms/waveforms.jl
with
176 additions
and
0 deletions
src/waveforms/generic.jl
0 → 100644
+
172
−
0
View file @
dc198ade
module
Generic
import
...
BuildingBlock
:
BuildingBlock
,
ContainerBlock
,
RFPulseBlock
import
...
Wait
:
WaitBlock
import
...
Readouts
:
InstantReadout
import
...
Gradients
:
GradientBlock
,
split_gradient
import
...
Variables
:
duration
,
start_time
,
qvec
,
bmat_gradient
,
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 all objects, where gradients, RF pulses, and/or readouts might overlap with each other.
All children need to be at least convertable into [`GenericWaveform`](@ref).
They might also override specific functions that can be computed more efficiently
"""
abstract type
AbstractWaveform
<:
ContainerBlock
end
abstract type
SpecificWaveform
<:
AbstractWaveform
end
"""
GenericWaveform(duration, waveform, interruptions)
Generic description that can capture any overlapping gradients, RF pulses, and/or readouts.
Interruptions are stores as tuples with 3 fields:
- `index`: which part of the `waveform` is being interrupted (cannot be a free variable).
- `time`: time of the interruption relative to the start of the `waveform` part (between 0 and the length of this part). This can be a variable.
- `block`: [`RFPulseBlock`](@ref) or [`InstantReadout`](@ref)
"""
struct
GenericWaveform
<:
AbstractWaveform
duration
::
VariableType
waveform
::
Vector
{
Union
{
WaitBlock
,
GradientBlock
}}
interruptions
::
Vector
{
NamedTuple
{(
:
index
,
:
time
,
:
block
),
(
Int64
,
<:
VariableType
,
<:
Union
{
RFPulseBlock
,
InstantReadout
})}}
end
"""
SingleInterrupted(grad_like_block, interruptions)
Represents a single part of the waveform within [`GenericWaveform`](@ref).
"""
struct
SingleInterrupted
{
T
<:
Union
{
WaitBlock
,
GradientBlock
}}
<:
AbstractWaveform
block
::
T
interruptions
::
Vector
{
NamedTuple
{(
:
index
,
:
time
,
:
block
),
(
Int64
,
Float64
,
<:
Union
{
RFPulseBlock
,
InstantReadout
})}}
end
"""
GenericWaveform(other_overlapping_block)
Converts any sub-type of [`SpecificWaveform`](@ref) into a [`GenericWaveform`](@ref).
This needs to be defined for every sub-type.
"""
function
GenericWaveform
end
waveform
(
go
::
GenericWaveform
)
=
go
.
waveform
interruptions
(
go
::
GenericWaveform
)
=
go
.
interruptions
duration
(
go
::
GenericWaveform
)
=
go
.
duration
duration
(
ao
::
AbstractWaveform
)
=
sum
(
duration
.
(
waveform
(
ao
)))
duration
(
single
::
SingleInterrupted
)
=
duration
(
single
.
block
)
pulses
(
ao
::
AbstractWaveform
)
=
[
pulse
for
(
_
,
_
,
pulse
)
in
ao
.
interruptions
if
pulse
isa
RFPulseBlock
]
readouts
(
ao
::
AbstractWaveform
)
=
[
readout
for
(
_
,
_
,
readout
)
in
ao
.
interruptions
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
]
@eval
function
$func_symbol
(
go
::
AbstractWaveform
,
args
...
;
kwargs
...
)
single_pulse
=
pulses
(
go
)
if
iszero
(
length
(
single_pulse
))
error
(
"Building block does not contain any RF pulse, so cannot compute
$
func_symbol."
)
elseif
lenth
(
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
(
go
::
Union
{
SpecificWaveform
,
GenericWaveform
})
=
1
:
length
(
waveform
(
go
))
function
Base.getindex
(
go
::
GenericWaveform
,
index
::
Integer
)
grad_like_block
=
waveform
(
go
)[
index
]
first_interrupt
=
findfirst
(
int
=>
int
[
2
]
==
index
,
interruptions
(
go
))
if
isnothing
(
first_interrupt
)
return
grad_like_block
else
last_interrupt
=
findlast
(
int
=>
int
[
2
]
==
index
,
go
.
interruptions
)
return
SingleInterrupted
(
grad_like_block
,
go
.
interruptions
[
first_interrupt
:
last_interrupt
])
end
end
function
start_time
(
go
::
Union
{
SpecificWaveform
,
GenericWaveform
},
index
::
Integer
)
sum
(
duration
.
(
waveform
(
go
)[
1
:
index
]))
end
function
get_part
(
so
::
SpecificWaveform
,
first
::
Union
{
Nothing
,
Number
},
last
::
Union
{
Nothing
,
Number
})
if
isnothing
(
first
)
if
isnothing
(
last
)
part
=
so
.
block
else
(
part
,
_
)
=
split_gradient
(
so
,
so
.
interruptions
[
last
][
1
])
end
else
tfirst
=
so
.
interruptions
[
first
][
1
]
if
isnothing
(
last
)
(
_
,
part
)
=
split_gradient
(
so
,
tfirst
)
else
(
_
,
part
,
_
)
=
split_gradient
(
so
,
tfirst
,
so
.
interruptions
[
last
][
1
])
end
end
return
part
end
function
get_parts
(
go
::
AbstractWaveform
,
first
::
Union
{
Nothing
,
Integer
},
last
::
Union
{
Nothing
,
Integer
})
inter
=
interruptions
(
go
)
form
=
waveform
(
go
)
whole_start_index
=
isnothing
(
first
)
?
0
:
inter
[
first
]
.
index
whole_final_index
=
isnothing
(
last
)
?
length
(
form
)
+
1
:
inter
[
first
]
.
index
if
whole_start_index
==
whole_final_index
return
[
split_gradient
(
form
[
whole_start_index
]
.
block
,
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
]
.
block
,
inter
[
first
]
.
time
)[
2
])
end
if
!
isnothing
(
last
)
push!
(
parts
,
split_gradient
(
form
[
whole_final_index
]
.
block
,
inter
[
last
]
.
time
)[
1
])
end
return
parts
end
# Computing gradient properties
for
func
in
(
:
qvec
,
:
bmat_gradient
)
@eval
$
func
(
ao
::
AbstractWaveform
,
args
...
,
kwargs
...
)
=
$
func
(
GenericWaveform
(
ao
),
args
...
;
kwargs
...
)
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
(
go
::
GenericOverlapping
,
index1
::
Union
{
Nothing
,
Integer
},
index2
::
Union
{
Nothing
,
Integer
})
@assert
index2
>=
index1
if
(
index1
isa
Number
)
&&
(
index1
==
index2
)
return
zeros
(
3
)
end
sum
(
qvec
.
(
get_parts
(
go
,
index1
,
index2
)))
end
qvec
(
ao
::
AbstractOverlapping
)
=
qvec
(
ao
,
nothing
,
nothing
)
function
bmat_gradient
(
go
::
GenericOverlapping
,
qstart
,
index1
::
Union
{
Nothing
,
Integer
},
index2
::
Union
{
Nothing
,
Integer
})
@assert
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
(
go
,
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
This diff is collapsed.
Click to expand it.
src/waveforms/waveforms.jl
0 → 100644
+
4
−
0
View file @
dc198ade
module
Overlapping
include
(
"generic.jl"
)
end
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment