Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docstrings Review #297

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
14 changes: 9 additions & 5 deletions KomaMRIBase/src/datatypes/Phantom.jl
Copy link
Member

@cncastillo cncastillo Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General comment (major revision).

Please make sure that the documentation is not more complex that the function; if the function is: f(x)=x^2, it does not need a docstring:

    y = f(x)

A function that calculates the square of a number.

# Arguments
- `x`: (`::Number`) input number

# Output
- `y`: (`::Number`) output number

# Example
...

This is true for the show functions and others, go one-by-one and ask the question "Is this docstring unnecessarily complex for the function?". I would argue that the only functions that need more in-depth documentation are the exported functions. If there is more docstring that code, we have a problem; do not bloat the code.

Copy link
Contributor Author

@beorostica beorostica Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that should be docstring when it is not necessary.

I did the excercise you proposed, however I couldn't find more autodescriptive functions which wouldn't require a docstring, according to my criteria.

For example, this one:

    Rx = rotx(θ::Real)

Rotates a three-dimensional vector or matrix with three rows counter-clockwise with respect
to the x-axis.

# Arguments
- `θ`: (`::Real`, `[rad]`) rotation angle

# Returns
- `Rx`: (`::Matrix{Real}`) rotation matrix

This function looks like is simple enough to don't require a docstring, however the units are important and the direction of the rotation too.

Maybe, I'm a little bit biased since I also try to keep uniformity in the docsstrings.

I eliminated the docstrings for Base.show methods in b1f8e54

Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""
obj = Phantom(name, x, y, z, ρ, T1, T2, T2s, Δw, Dλ1, Dλ2, Dθ, ux, uy, uz)

The Phantom struct. Most of its field names are vectors, with each element associated with
a property value representing a spin. This struct serves as an input for the simulation.
The `Phantom` struct has field names that are vectors associated with spin properties. It
allows accessing specific spin property values by indexing these vectors. This struct serves
as input for the simulation.

# Arguments
- `name`: (`::String`) phantom name
Expand Down Expand Up @@ -181,7 +182,8 @@ Creates a two-dimensional brain Phantom struct.
- https://brainweb.bic.mni.mcgill.ca/brainweb

# Keywords
- `axis`: (`::String`, `="axial"`, opts=[`"axial"`, `"coronal"`, `"sagittal"`]) orientation of the phantom
- `axis`: (`::String`, `="axial"`, opts=[`"axial"`, `"coronal"`, `"sagittal"`]) orientation
of the phantom
Comment on lines +185 to +186
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the extra line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was simply trying to adhere to the 92-character line length limit.

- `ss`: (`::Integer`, `=4`) subsampling parameter in all axis

# Returns
Expand Down Expand Up @@ -279,7 +281,7 @@ function brain_phantom2D(; axis="axial", ss=4)
end

"""
obj = brain_phantom3D(; ss=4)
obj = brain_phantom3D(; ss=4, start_end=[160, 200])

Creates a three-dimentional brain Phantom struct.

Expand All @@ -292,6 +294,8 @@ Creates a three-dimentional brain Phantom struct.

# Keywords
- `ss`: (`::Integer`, `=4`) subsampling parameter in all axes
- `start_end`: (`::Integer`, `=[160, 200]`) start and end indices along the z-axis.
Acceptable values range from 1 to 362

# Returns
- `obj`: (`::Phantom`) 3D Phantom struct
Expand All @@ -303,7 +307,7 @@ julia> obj = brain_phantom3D(; ss=5)
julia> plot_phantom_map(obj, :ρ)
```
"""
function brain_phantom3D(;ss=4,start_end=[160, 200])
function brain_phantom3D(; ss=4, start_end=[160, 200])

# Get data from .mat file
path = @__DIR__
Expand Down
4 changes: 2 additions & 2 deletions KomaMRIBase/src/datatypes/Scanner.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
sys = Scanner(B0, B1, Gmax, Smax, ADC_Δt, seq_Δt, GR_Δt, RF_Δt,
RF_ring_down_T, RF_dead_time_T, ADC_dead_time_T)

The Scanner struct. It contains hardware limitations of the MRI resonator. It is an input
for the simulation.
The `Scanner` struct contains the hardware limitations of an MRI resonator and serves as an
input for the simulation.

# Arguments
- `B0`: (`::Real`, `=1.5`, `[T]`) main magnetic field strength
Expand Down
94 changes: 44 additions & 50 deletions KomaMRIBase/src/datatypes/Sequence.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@
seq = Sequence(GR::Array{Grad,1}, RF::Array{RF,1})
seq = Sequence(GR::Array{Grad,1}, RF::Array{RF,1}, A::ADC, DUR, DEF)

The Sequence struct. It contains events of an MRI sequence. Most field names (except for the
DEF field) consist of matrices or vectors, where each column index represents a sequence
block. This struct serves as an input for the simulation.
The Sequence struct contains events of an MRI sequence. Most field names, except for the DEF
field, consist of matrices or vectors. In these matrices, each column index represents a
sequence block. This struct serves as input for the simulation.

# Arguments
- `GR`: (`::Matrix{Grad}`) gradient matrix. Rows for x-y-z amplitudes and columns are for blocks
- `GR`: (`::Matrix{Grad}`) gradient matrix. Rows for x-y-z amplitudes and columns are fo blocks
- `RF`: (`::Matrix{RF}`) RF matrix. The 1 row is for the coil and columns are for blocks
- `ADC`: (`::Array{ADC,1}`) ADC block vector
- `DUR`: (`::Vector`, `[s]`) duration block vector
- `DEF`: (`::Dict{String, Any}`) dictionary with relevant information of the sequence.
Possible keys could be [`"AdcRasterTime"`, `"GradientRasterTime"`, `"Name"`, `"Nz"`,
Possible keys include [`"AdcRasterTime"`, `"GradientRasterTime"`, `"Name"`, `"Nz"`,
`"Num_Blocks"`, `"Nx"`, `"Ny"`, `"PulseqVersion"`, `"BlockDurationRaster"`,
`"FileName"`, `"RadiofrequencyRasterTime"`]

Expand Down Expand Up @@ -80,17 +80,7 @@ Sequence(GR::Array{Grad,1}, RF::Array{RF,1})= Sequence(reshape(GR, :, 1), reshap
Sequence(GR::Array{Grad,1}, RF::Array{RF,1}, A::ADC, DUR, DEF)= Sequence(reshape(GR, :, 1), reshape(RF, 1, :), [A], [DUR], DEF)
Sequence() = Sequence([Grad(0, 0)])

"""
str = show(io::IO, s::Sequence)

Displays information about the Sequence struct `s` in the julia REPL.

# Arguments
- `s`: (`::Sequence`) Sequence struct

# Returns
- `str` (`::String`) output string message
"""
# Display on the REPL
Base.show(io::IO, s::Sequence) = begin
compact = get(io, :compact, false)
if !compact
Expand Down Expand Up @@ -140,13 +130,13 @@ size(x::Sequence) = size(x.GR[1,:])

"""
y = is_ADC_on(x::Sequence)
y = is_ADC_on(x::Sequence, t::Union{Array{Float64,1}, Array{Float64,2}})
y = is_ADC_on(x::Sequence, t::AbstractVecOrMat})

Tells if the sequence `seq` has elements with ADC active, or active during time `t`.

# Arguments
- `x`: (`::Sequence`) sequence struct
- `t`: (`::Union{Array{Float64,1}, Array{Float64,2}}`, `[s]`) time to check
- `t`: (`::AbstractVecOrMat`, `[s]`) time to check

# Returns
- `y`: (`::Bool`) boolean that tells whether or not the ADC in the sequence is active
Expand All @@ -170,13 +160,13 @@ end

"""
y = is_RF_on(x::Sequence)
y = is_RF_on(x::Sequence, t::Vector{Float64})
y = is_RF_on(x::Sequence, t::Vector{Real})

Comment on lines 162 to 164
Copy link
Member

@cncastillo cncastillo Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename x to seq everywhere in the docstrings (if x is a Sequence).

Rename x to rf everywhere in the docstrings (if x is an RF).

Rename x to gr everywhere in the docstrings (if x is a Grad).

Rename x to adc everywhere in the docstrings (if x is an ADC).

Rename x to delay everywhere in the docstrings (if x is a Delay).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 949850c

Tells if the sequence `seq` has elements with RF active, or active during time `t`.

# Arguments
- `x`: (`::Sequence`) Sequence struct
- `t`: (`::Vector{Float64}`, `[s]`) time to check
- `t`: (`::AbstractVector{Real}`, `[s]`) time to check

# Returns
- `y`: (`::Bool`) boolean that tells whether or not the RF in the sequence is active
Expand Down Expand Up @@ -286,7 +276,7 @@ end
"""
T = dur(x::Sequence)

The total duration of the sequence in [s].
The total duration of the sequence in seconds.

# Arguments
- `x`: (`::Sequence`) Sequence struct
Expand All @@ -306,7 +296,7 @@ always zero, and the final time corresponds to the duration of the sequence.
- `seq`: (`::Sequence`) Sequence struct

# Returns
- `T0`: (`::Vector`, `[s]`) start times of the blocks in a sequence
- `T0`: (`::Vector{Real}`, `[s]`) start times of the blocks in a sequence
"""
get_block_start_times(seq::Sequence) = cumsum([0; seq.DUR], dims=1)

Expand Down Expand Up @@ -360,16 +350,14 @@ Generates a trapezoidal waveform vector.

# Arguments
- `A`: (`::Real`) amplitude
- `t`: (`::Vector{Float64}`, `[s]`) times to evaluate (actually it's a `1-row
::Matrix{Float64}`)
- `t`: (`::Matrix{Real}`, `[s]`) times to evaluate (it's a `1-row matrix`)
- `ΔT`: (`::Real`, `[s]`) time duration of the top-flat
- `ζ1`: (`::Real`, `[s]`) rise time duration
- `ζ2`: (`::Real`, `[s]`) fall time duration
- `delay`: (`::Real`, `[s]`) delay time

# Returns
- `y`: (`::Vector{Float64}`) trapezoidal waveform (actually it's a `1-row
::Matrix{Float64}`)
- `y`: (`::Matrix{Real}`) trapezoidal waveform (it's a `1-row matrix`)
"""
⏢(A, t, ΔT, ζ1, ζ2, delay) = begin
if sum(abs.(A)) != 0 && ΔT+ζ1+ζ2 != 0 # If no event just ignore calculations
Expand Down Expand Up @@ -454,15 +442,16 @@ end
"""
B1, Δf_rf = get_rfs(seq::Sequence, t)

Returns the RF pulses and the delta frequency.
Returns the amplitude and frequency difference with respect to the resonance frequency
contained in a sequence structure.

# Arguments
- `seq`: (`::Sequence`) Sequence struct
- `t`: (`1-row ::Matrix{Float64}`, `[s]`) time points
- `t`: (`1-row ::Matrix{Real}`, `[s]`) time points

# Returns
- `B1`: (`1-row ::Matrix{ComplexF64}`, `[T]`) vector of RF pulses
- `Δf_rf`: (`1-row ::Matrix{Float64}`, `[Hz]`) delta frequency vector
- `B1`: (`1-row ::Matrix{Complex}}`, `[T]`) vector of RF pulses
- `Δf_rf`: (`1-row ::Matrix{Real}`, `[Hz]`) delta frequency vector
"""
get_rfs(seq::Sequence, t) = begin
ϵ = MIN_RISE_TIME
Expand All @@ -487,22 +476,22 @@ Returns all the flip angles of the RF pulses in the sequence `x`.
- `x`: (`::Sequence`) Sequence struct

# Returns
- `y`: (`::Vector{Float64}`, `[deg]`) flip angles
- `y`: (`::Vector{Real}`, `[deg]`) flip angles
"""
get_flip_angles(x::Sequence) = get_flip_angle.(x.RF)[:]

"""
rf_idx, rf_type = get_RF_types(seq, t)

Get RF centers and types (excitation or precession). Useful for k-space calculations.
Get the RF centers and types (excitation or precession). Useful for k-space calculations.

# Arguments
- `seq`: (`::Sequence`) Sequence struct
- `t`: (`::Vector{Float64}`, `[s]`) time values
- `t`: (`::Vector{Real}`, `[s]`) time values

# Returns
- `rf_idx`: (`::Vector{Int64}`) indices of the RF centers
- `rf_type`: (`::Vector{Int64}`, opts: [`0`, `1`]) RF type (`0`: excitation, `1`:
- `rf_idx`: (`::Vector{Integer}`) indices of the RF centers
- `rf_type`: (`::Vector{Integer}`, opts: [`0`, `1`]) RF type (`0`: excitation, `1`:
precession)
"""
function get_RF_types(seq, t)
Expand Down Expand Up @@ -536,13 +525,15 @@ Outputs the designed k-space trajectory of the Sequence `seq`.
- `seq`: (`::Sequence`) Sequence struct
- `Δt`: (`::Real`, `=1`, `[s]`) nominal delta time separation between two time samples
for ADC acquisition and Gradients
- `skip_rf`: (`::Vector{Bool}`, `=zeros(Bool, sum(is_RF_on.(seq)))`) boolean vector
indicating if the RFs should be considered for the k-space computation, with a length
equal to the number of active RF blocks in a sequence

# Returns
- `kspace`: (`3-column ::Matrix{Float64}`) kspace
- `kspace_adc`: (`3-column ::Matrix{Float64}`) adc kspace
- `kspace`: (`3-column ::Matrix{Real}`) k-space
- `kspace_adc`: (`3-column ::Matrix{Real}`) k-space sampled at ADC times
"""
get_kspace(seq::Sequence; Δt=1,
skip_rf=zeros(Bool, sum(is_RF_on.(seq)))) = begin
get_kspace(seq::Sequence; Δt=1, skip_rf=zeros(Bool, sum(is_RF_on.(seq)))) = begin
t, Δt = get_variable_times(seq; Δt)
Gx, Gy, Gz = get_grads(seq, t)
G = Dict(1=>Gx, 2=>Gy, 3=>Gz)
Expand Down Expand Up @@ -594,10 +585,13 @@ Outputs the designed M1 of the Sequence `seq`.
- `seq`: (`::Sequence`) Sequence struct
- `Δt`: (`::Real`, `=1`, `[s]`) nominal delta time separation between two time samples
for ADC acquisition and Gradients
- `skip_rf`: (`::Vector{Bool}`, `=zeros(Bool, sum(is_RF_on.(seq)))`) boolean vector
indicating if the RFs should be considered for the M1 computation, with a length
equal to the number of active RF blocks in a sequence

# Returns
- `M1`: (`3-column ::Matrix{Float64}`) First moment
- `M1_adc`: (`3-column ::Matrix{Float64}`) First moment sampled at ADC points
- `M1`: (`3-column ::Matrix{Real}`) first moment
- `M1_adc`: (`3-column ::Matrix{Real}`) first moment sampled at ADC times
"""
get_M1(seq::Sequence; Δt=1, skip_rf=zeros(Bool, sum(is_RF_on.(seq)))) = begin
t, Δt = get_variable_times(seq; Δt)
Expand Down Expand Up @@ -654,8 +648,8 @@ Outputs the designed M2 of the Sequence `seq`.
for ADC acquisition and Gradients

# Returns
- `M2`: (`3-column ::Matrix{Float64}`) Second moment
- `M2_adc`: (`3-column ::Matrix{Float64}`) Second moment sampled at ADC points
- `M2`: (`3-column ::Matrix{Real}`) second moment
- `M2_adc`: (`3-column ::Matrix{Real}`) second moment sampled at ADC times
"""
get_M2(seq::Sequence; Δt=1) = begin
t, Δt = get_variable_times(seq; Δt)
Expand Down Expand Up @@ -695,16 +689,16 @@ end
"""
SR, SR_adc = get_slew_rate(seq::Sequence; Δt=1)

Outputs the designed slew rate of the Sequence `seq`.
Outputs the slew rate of the Sequence `seq`.

# Arguments
- `seq`: (`::Sequence`) Sequence struct
- `Δt`: (`::Real`, `=1`, `[s]`) nominal delta time separation between two time samples
for ADC acquisition and Gradients

# Returns
- `SR`: (`3-column ::Matrix{Float64}`) Slew rate
- `SR_adc`: (`3-column ::Matrix{Float64}`) Slew rate sampled at ADC points
- `SR`: (`3-column ::Matrix{Real}`) slew rate
- `SR_adc`: (`3-column ::Matrix{Real}`) slew rate sampled at ADC times
"""
get_slew_rate(seq::Sequence; Δt=1) = begin
t, Δt = get_variable_times(seq; Δt)
Expand Down Expand Up @@ -740,17 +734,17 @@ end
"""
EC, EC_adc = get_eddy_currents(seq::Sequence; Δt=1, λ=80e-3)

Outputs the designed eddy currents of the Sequence `seq`.
Outputs the Eddy currents of the Sequence `seq`.

# Arguments
- `seq`: (`::Sequence`) Sequence struct
- `Δt`: (`::Real`, `=1`, `[s]`) nominal delta time separation between two time samples
for ADC acquisition and Gradients
- `λ`: (`::Float64`, `=80e-3`, `[s]`) eddy current decay constant time
- `λ`: (`::Real`, `=80e-3`, `[s]`) Eddy current decay constant time

# Returns
- `EC`: (`3-column ::Matrix{Float64}`) Eddy currents
- `EC_adc`: (`3-column ::Matrix{Float64}`) Eddy currents sampled at ADC points
- `EC`: (`3-column ::Matrix{Real}`) Eddy currents
- `EC_adc`: (`3-column ::Matrix{Real}`) Eddy currents sampled at ADC times
"""
get_eddy_currents(seq::Sequence; Δt=1, λ=80e-3) = begin
t, Δt = get_variable_times(seq; Δt)
Expand Down
32 changes: 15 additions & 17 deletions KomaMRIBase/src/datatypes/sequence/ADC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
adc = ADC(N, T, delay)
adc = ADC(N, T, delay, Δf, ϕ)

The ADC struct represents the Analog to Digital Converter (ADC) of a sequence event.
The ADC struct represents the Analog to Digital Converter (ADC) event of a sequence.

# Arguments
- `N`: (`::Int64`) number of acquired samples
- `T`: (`::Float64`, [`s`]) duration to acquire the samples
- `delay`: (`::Float64`, [`s`]) delay time to start the acquisition
- `Δf`: (`::Float64`, [`Hz`]) delta frequency. It is meant to compensate RF pulse phases
- `ϕ`: (`::Float64`, `[rad]`) phase. It is meant to compensate RF pulse phases
- `N`: (`::Integer`) number of acquired samples
- `T`: (`::Real`, [`s`]) duration to acquire the samples
- `delay`: (`::Real`, [`s`]) delay time to start the acquisition
- `Δf`: (`::Real`, [`Hz`]) delta frequency. It is meant to compensate RF pulse phases
- `ϕ`: (`::Real`, `[rad]`) phase. It is meant to compensate RF pulse phases

# Returns
- `adc`: (`::ADC`) ADC struct
Expand Down Expand Up @@ -48,17 +48,17 @@ end
"""
y = getproperty(x::Vector{ADC}, f::Symbol)

Overloads Base.getproperty(). It is meant to access properties of the ADC vector `x`
directly without the need to iterate elementwise.
Overloads Base.getproperty() to facilitate direct access to properties of the ADC vector `x`
without the need for elementwise iteration.

# Arguments
- `x`: (`::Vector{ADC}`) vector of ADC structs
- `f`: (`::Symbol`, opts: [`:N`, `:T`, `:delay`, `:Δf`, `:ϕ`, `:dur`]) input symbol that
represents a property of the ADC structs

# Returns
- `y`: (`::Vector{Any}`) vector with the property defined by the `f` for all elements of
the ADC vector `x`
- `y`: (`::Vector{Any}`) vector with the property defined by `f` for all elements of the ADC
vector `x`
"""
getproperty(x::Vector{ADC}, f::Symbol) = begin
if f == :dur
Expand All @@ -79,7 +79,7 @@ Returns an array of times when the samples of the sequence `seq` are acquired.
- `seq`: (`::Sequence`) sequence struct

# Returns
- `times`: (`::Vector{Float64}`, `[s]`) time array when samples are acquired
- `times`: (`::Vector{Float64}`, `[s]`) time array during sample acquisiton
"""
function get_adc_sampling_times(seq)
T0 = get_block_start_times(seq)
Expand All @@ -103,17 +103,15 @@ end
"""
phase = get_adc_phase_compensation(seq)

Returns the array of phases for every acquired sample in the sequence `seq`.

!!! note
This function is useful to compensate the phase when the RF pulse has a phase too. Refer
to the end of the [`run_sim_time_iter`](@ref) function to see its usage.
Returns the array of phases for each acquired sample in the sequence `seq`. This function is
particularly useful for compensating the phase when the RF pulse also has a phase. Refer to
the end of the [`run_sim_time_iter`](@ref) function to see its usage.

# Arguments
- `seq`: (`::Sequence`) sequence struct

# Returns
- `phase`: (`::Vector{Complex{Int64}}`, `[rad]`) array of phases for every acquired sample
- `phase`: (`::Vector{Complex{Float64}}`, `[rad]`) array of phases for each acquired sample
"""
function get_adc_phase_compensation(seq)
phase = ComplexF32[]
Expand Down
Loading
Loading