Skip to content
Snippets Groups Projects
Unverified Commit 1427f18a authored by Michiel Cottaar's avatar Michiel Cottaar
Browse files

Write MRIBuilder.Sequence to pulseq file

parent ff2ab433
No related branches found
No related tags found
1 merge request!1Add writing to Pulseq files
......@@ -3,14 +3,16 @@ Module converting MRIBuilder sequences to and from sequences recognised by [`Pul
"""
module Pulseq
import Interpolations: linear_interpolation
import ..PulseqIO.Types: PulseqSequence, PulseqBlock, PulseqTrapezoid, PulseqGradient
import ...Containers: Sequence, BuildingBlock
import ...Components: GenericPulse, ADC
import ..PulseqIO.Types: PulseqSequence, PulseqBlock, PulseqTrapezoid, PulseqGradient, PulseqRFPulse, PulseqShape, PulseqADC, PulseqExtension
import ...Containers: Sequence, BuildingBlock, BaseBuildingBlock, events, waveform, iter_blocks
import ...Components: GenericPulse, ADC, RFPulseComponent
import ...Scanners: Scanner
import ...Variables: duration, nsamples, dwell_time, make_generic
function Sequence(pulseq::PulseqSequence; scanner=nothing, B0=3)
function Sequence(pulseq::PulseqSequence; scanner=nothing, B0=nothing)
if isnothing(scanner)
scanner = Scanner(B0=B0)
use_B0 = isnothing(B0) ? get(pulseq.definitions, :B0, 3.) : B0
scanner = Scanner(B0=use_B0)
end
blocks = BuildingBlock.(pulseq.blocks; pulseq.definitions...)
return Sequence(blocks; name=Symbol(get(pulseq.definitions, :name, "from_pulseq")), scanner=scanner)
......@@ -88,4 +90,80 @@ function _get_amplitude(grad::PulseqGradient, time::Number, raster::Number)
end
function PulseqSequence(seq::Sequence{S}) where {S}
definitions = (
name=S,
AdcRasterTime=1e-9,
BlockDurationRaster=1e-9,
RadiofrequencyRasterTime=1e-9,
GradientRasterTime=1e-9,
TotalDuration=duration(seq) * 1e-3,
B0=seq.scanner.B0,
)
blocks = [PulseqBlock(block; definitions...) for (_, block) in iter_blocks(seq)]
return PulseqSequence(
v"1.4.0",
definitions,
blocks
)
end
function PulseqBlock(block::BaseBuildingBlock; BlockDurationRaster, AdcRasterTime, kwargs...)
rf = nothing
adc = nothing
for (delay, event) in events(block)
if event isa RFPulseComponent
if !isnothing(rf)
error("Pulseq does not support a single building block containing multiple RF pulses.")
end
gen = make_generic(event)
rf = PulseqRFPulse(
maximum(gen.amplitude) * 1e3,
PulseqShape(gen.amplitude ./ maximum(gen.amplitude)),
PulseqShape(deg2rad.(gen.phase)),
PulseqShape(gen.time .* 1e-3),
Int(div(delay, 1e-3)),
0.,
0.
)
elseif event isa ADC
if !isnothing(rf)
error("Pulseq does not support a single building block containing multiple ADC events.")
end
adc = PulseqADC(
nsamples(event),
div(dwell_time(event), AdcRasterTime),
Int(div(delay, 1e-3)),
0., 0.
)
else
error("Cannot write $(typeof(event)) to Pulseq.")
end
end
grads = []
times = [t for (t, _) in waveform(block)]
for dim in 1:3
amplitudes = [g[dim] for (_, g) in waveform(block)]
if iszero(maximum(abs.(amplitudes); init=0.))
push!(grads, nothing)
else
push!(grads, PulseqGradient(
maximum(amplitudes) * 1e3,
PulseqShape(amplitudes ./ maximum(amplitudes)),
PulseqShape(times .* 1e-3),
0.,
))
end
end
return PulseqBlock(
Int(div(1e-3 * duration(block), BlockDurationRaster)),
rf,
grads...,
adc,
Tuple{PulseqExtension, Int}[]
)
end
end
\ No newline at end of file
......@@ -4,6 +4,7 @@ function parse_section(section:: PulseqSection{:definitions}; kwargs...)
end
_to_string_value(value::AbstractString) = value
_to_string_value(value::Symbol) = string(value)
_to_string_value(value::Number) = string(value)
_to_string_value(value::Vector) = join(_to_string_value.(value), " ")
......
......@@ -12,6 +12,7 @@ include("components.jl")
include("parsers/parsers.jl")
include("parse_sections.jl")
import .Types: PulseqSequence
"""
......
......@@ -4,7 +4,7 @@ include("pulseq_io/pulseq_io.jl")
include("pulseq.jl")
import Serialization: serialize, deserialize
import .PulseqIO: read_pulseq
import .PulseqIO: read_pulseq, write_pulseq, PulseqSequence
import ..Containers: Sequence
......@@ -14,7 +14,7 @@ function read_sequence(filename::AbstractString, args...; kwargs...)
end
end
function read_sequence(io::IO; format=nothing, kwargs...)
function read_sequence(io::IO; format=nothing, B0=nothing, scanner=nothing,kwargs...)
if isnothing(format)
pos = position(io)
for format in (:pulseq, :serialize)
......@@ -27,7 +27,7 @@ function read_sequence(io::IO; format=nothing, kwargs...)
error("Could not read the input filename. Tried all formats (:pulseq/:serialize).")
end
if format == :pulseq
return Sequence(read_pulseq(io, kwargs...))
return Sequence(read_pulseq(io, kwargs...), B0=B0, scanner=scanner)
elseif format == :serialize
return deserialize(io, kwargs...)
else
......@@ -42,8 +42,10 @@ function write_sequence(filename::AbstractString, args...; kwargs...)
end
end
function write_sequence(io::IO, sequence; format::Symbol=:serialize)
if format == :serialize
function write_sequence(io::IO, sequence; format::Symbol=:pulseq)
if format == :pulseq
write_pulseq(io, PulseqSequence(sequence))
elseif format == :serialize
serialize(io, sequence)
else
error("Unrecognised selected format for output ($format). Only :serialize is supported..")
......
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