Skip to content

Commit

Permalink
Commit of the following:
Browse files Browse the repository at this point in the history
- Finish lit-1-phantom.jl
- New lit-3-phantom-format.jl
- Upload svg files for phantom file tree
- Update cross references
  • Loading branch information
pvillacorta committed Oct 11, 2024
1 parent 64c02fa commit 38b96de
Show file tree
Hide file tree
Showing 19 changed files with 4,117 additions and 33 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ KomaMRI.jl is a Julia package for highly efficient ⚡ MRI simulations. KomaMRI
## News

- **(1 Oct 2024)** [KomaMRI v0.9](https://github.com/JuliaHealth/KomaMRI.jl/releases/tag/v0.9.0): device-agnostic simulations, improved performance (**4-5x faster and 80x less memory**), distributed simulations, GPU benchmarking, mix-and-match motion definitions, improved dynamic phantom plotting, and a new phantom file format!
- **(29 Aug 2024)** Our first GSoC student, Ryan Kierulf, presented his fantastic work at the JuliaHealth monthly meeting 🥳! (presentation available [here](https://www.youtube.com/watch?v=R6Z20G0J4bM)) More info in the docs: [GPU Parallelization](https://juliahealth.org/KomaMRI.jl/dev/explanation/4-gpu-explanation/), [Distributed Simulations](https://juliahealth.org/KomaMRI.jl/dev/how-to/4-run-distributed-simulations/) and [Ryan's JuliaHealth blog](https://juliahealth.org/JuliaHealthBlog/posts/ryan-gsoc/Ryan_GSOC.html)
- **(29 Aug 2024)** Our first GSoC student, Ryan Kierulf, presented his fantastic work at the JuliaHealth monthly meeting 🥳! (presentation available [here](https://www.youtube.com/watch?v=R6Z20G0J4bM)) More info in the docs: [GPU Parallelization](https://juliahealth.org/KomaMRI.jl/dev/explanation/7-gpu-explanation/), [Distributed Simulations](https://juliahealth.org/KomaMRI.jl/dev/how-to/4-run-distributed-simulations/) and [Ryan's JuliaHealth blog](https://juliahealth.org/JuliaHealthBlog/posts/ryan-gsoc/Ryan_GSOC.html)
- **(7 Dec 2023)** Koma was present in [MRI Together](https://mritogether.esmrmb.org/) 😼. The talk is available [here](https://www.youtube.com/watch?v=9mRQH8um4-A). Also, I uploaded the promised [educational example](https://juliahealth.org/KomaMRI.jl/stable/tutorial-pluto/01-gradient-echo-spin-echo/).
- **(17 Nov 2023)** Pretty excited of being part of [ISMRM Pulseq's virtual meeting](https://github.com/pulseq/ISMRM-Virtual-Meeting--November-15-17-2023). The slides available [here](https://github.com/pulseq/ISMRM-Virtual-Meeting--November-15-17-2023/blob/35a8da7eaa0bf42f2127e1338a440ccd4e3ef53c/slides/day3_KomaMRI_simulator_Quantitative_MRI.pdf).
- **(27 Jul 2023)** I gave a talk at MIT 😄 for [JuliaCon 2023](https://juliacon.org/2023/)! A video of the presentation can be seen [here](https://www.youtube.com/watch?v=WVT9wJegC6Q).
Expand Down Expand Up @@ -117,7 +117,7 @@ KomaUI()
Press the button that says "Simulate!" to do your first simulation :). Then, a notification will emerge telling you that the simulation was successful. In this notification, you can either select to (1) see the Raw Data or (2) to proceed with the reconstruction.

> [!IMPORTANT]
> Starting from **KomaMRI v0.9** we are using [package extensions](https://pkgdocs.julialang.org/v1/creating-packages/#Conditional-loading-of-code-in-packages-(Extensions)) to deal with GPU dependencies, meaning that to run simulations on the GPU, installing (`add CUDA/AMDGPU/Metal/oneAPI`) and loading (`using CUDA/AMDGPU/Metal/oneAPI`) the desired backend will be necessary (see [GPU Parallelization](https://JuliaHealth.github.io/KomaMRI.jl/dev/explanation/4-gpu-explanation) and [Tested compatibility](#tested-compatibility)).
> Starting from **KomaMRI v0.9** we are using [package extensions](https://pkgdocs.julialang.org/v1/creating-packages/#Conditional-loading-of-code-in-packages-(Extensions)) to deal with GPU dependencies, meaning that to run simulations on the GPU, installing (`add CUDA/AMDGPU/Metal/oneAPI`) and loading (`using CUDA/AMDGPU/Metal/oneAPI`) the desired backend will be necessary (see [GPU Parallelization](https://JuliaHealth.github.io/KomaMRI.jl/dev/explanation/7-gpu-explanation) and [Tested compatibility](#tested-compatibility)).
## How to Contribute
KomaMRI exists thanks to all our contributors:
Expand Down
824 changes: 824 additions & 0 deletions docs/src/assets/ph-action-types-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
817 changes: 817 additions & 0 deletions docs/src/assets/ph-action-types-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
683 changes: 683 additions & 0 deletions docs/src/assets/ph-phantom-file-format-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
682 changes: 682 additions & 0 deletions docs/src/assets/ph-phantom-file-format-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
200 changes: 200 additions & 0 deletions docs/src/assets/ph-spinspan-types-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
198 changes: 198 additions & 0 deletions docs/src/assets/ph-spinspan-types-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
277 changes: 277 additions & 0 deletions docs/src/assets/ph-timepan-types-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
277 changes: 277 additions & 0 deletions docs/src/assets/ph-timepan-types-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ mutable struct Sequence
end
```

As you can see, a **Sequence** struct contains 5 field names: ''DEF'' contains information for reconstruction steps (so it is not mandatory to fill it), ''DUR'' is a vector that contains the time durations of each block, ''ADC'' is also a vector with the acquisition samples for every block (an vector of **ADC** structs), ''GR'' is a 2D matrix which 3 rows representing the x-y-z gradients and columns having the samples of each block (a matrix of **Grad** structs) and ''RF'' is also a 2D matrix where each row represents a different coil and the columns are for different block samples too (a matrix of **RF** structs). The **RF**, **Grad** and **ADC** are MRI events that will be explained in the section [Events Definitions](2-seq-events.md).
As you can see, a **Sequence** struct contains 5 field names: ''DEF'' contains information for reconstruction steps (so it is not mandatory to fill it), ''DUR'' is a vector that contains the time durations of each block, ''ADC'' is also a vector with the acquisition samples for every block (an vector of **ADC** structs), ''GR'' is a 2D matrix which 3 rows representing the x-y-z gradients and columns having the samples of each block (a matrix of **Grad** structs) and ''RF'' is also a 2D matrix where each row represents a different coil and the columns are for different block samples too (a matrix of **RF** structs). The **RF**, **Grad** and **ADC** are MRI events that will be explained in the section [Events Definitions](5-seq-events.md).

!!! warning
So far, **KomaMRI** can only manage one coil for RF excitations. However, in future versions, parallel transmit pTX will be managed by adding more ``rows'' to the RF matrix of the Sequence field name.
Expand Down Expand Up @@ -88,7 +88,7 @@ julia> seq.DUR
0.0004042313086942605
```

Additionally, you can access a subset of blocks in a **Sequence** by slicing or indexing. The result will also be a **Sequence** struct, allowing you to perform the same operations as you would with a full Sequence. For example, if you want to analyze the first 11 blocks, you can do the following:
Additionally, you can access a subset of blocks in a **Sequence** by slicing or indexing. The result will also be a **Sequence** struct, allowing you to perform the same operations as you would with a full Sequence (just a heads-up: this is analogous for the [Phantom](1-phantom.md) structure). For example, if you want to analyze the first 11 blocks, you can do the following:
```julia-repl
julia> seq[1:11]
Sequence[ τ = 3.837 ms | blocks: 11 | ADC: 5 | GR: 11 | RF: 1 | DEF: 5 ]
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
108 changes: 93 additions & 15 deletions docs/src/explanation/lit-1-phantom.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,25 @@ using KomaMRI # hide

# The first input argument that **KomaMRI** needs for simulating is the phantom.

# This section goes over the concept of digital phantom
# and shows how it applies to the specific case of **KomaMRI**.
# We'll go into detail about the [`Phantom`](@ref) structure
# and present the ''.phantom'' file format, which makes it easy
# to share phantoms and reproduce experiments on any computer.
# This section goes over the concept of digital phantom and shows how it applies to the specific case
# of **KomaMRI**. We'll go into detail about the [`Phantom`](@ref) structure and its supported operations.

# ## Digital Phantom

# A digital phantom is basically a computer model of a physical object
# (like the human body or a body part) which is used in simulations
# to mimic the characteristics and behaviour that would be obtained
# from real MRI. Instead of using a physical object for testing,
# the digital phantom allows for virtual experiments.
# A digital phantom is basically a computer model of a physical object (like the human body or a body part)
# which is used in simulations to mimic the characteristics and behaviour that would be obtained from
# real MRI. Instead of using a physical object for testing, the digital phantom allows for virtual experiments.

# This computer model should essentially contain information about
# the position and/or displacements of the tissues, as well as
# their MRI-related (T1, T2, PD, off-resonance...) values.
# This computer model should essentially contain information about the position and/or displacements
# of the tissues, as well as their MRI-related (T1, T2, PD, off-resonance...) values.

# ## KomaMRI Phantom Overview
# In Koma, a phantom is made up of a set of spins (which in many cases are also known as ''isochromats'').
# Each spin is independent of the others in terms of properties, position and state.
# This is a key feature of **KomaMRI**, as it is explained in the [Simulation](6-simulation.md) section.

# **KomaMRI** relies on the [`Phantom`](@ref) struct to define its digital phantom:
# Let's take a look at the definition of the [`Phantom`](@ref) struct
# inside Koma's source code to see what it looks like:
# ```julia
# @with_kw mutable struct Phantom{T<:Real}
# name::String = "spins"
Expand All @@ -46,4 +44,84 @@ using KomaMRI # hide
# end
# ```

## Phantom File Format
# This structure consists of several elements. Most of them are vectors, except for
# the `name` (self-explanatory) and `motion` (explained below) fields.
# These vectors represent object properties, with each element holding a value associated
# with a single magnetization (i.e. a single spin).
# Specifically, `x`, `y` and `z` are the spatial (starting) coordinates of each spin.
# `ρ` stands for the proton density, and `T1`, `T2` and `T2s` (standing for T2*)
# are the well-known relaxation times. `Δw` accounts for off-resonance effects.
# `Dλ1`, `Dλ2` and `Dθ` are diffusion-related fields which are not in use at the moment.
# Last, the `motion` field stands for spin displacements, which are added to `x`, `y` and `z`
# when simulating in order to obtain the spin positions at each time step. For more information about
# motion, refer to [Motion](2-motion.md) section.

# To get an even better understanding on how it works, let's look at an example of a brain phantom:

obj = brain_phantom2D()

# You can visualize the **Phantom** struct using the [`plot_phantom_map`](@ref) function,
# which is part of the **KomaMRIPlots** subdependency. This function plots the magnitude of a property for
# each magnetization at a specific spatial position. You can observe properties such as proton density
# and relaxation times, so feel free to replace the `:ρ` symbol with another property of the phantom in the example below:

p1 = plot_phantom_map(obj, ; height=450)

#md savefig(p1, "../assets/doc-1-phantom.html") # hide
#jl display(p1)

#md # ```@raw html
#md # <center><object type="text/html" data="../../assets/doc-1-phantom.html" style="width:85%; height:470px;"></object></center>
#md # ```

# You can access and filter information for the all the field names of a **Phantom** using the dot notation:
obj.name
#-
obj.x
#-
obj.motion

# ## Phantom Operations

# In addition, **KomaMRI** supports some phantom operations:

# ### Phantom Subset

# It is possible to access a subset of spins in a **Phantom** by slicing or indexing. The result will also be a
# **Phantom** struct, allowing you to perform the same operations as you would with a full Phantom:

obj[1:1000]
p2 = plot_phantom_map(obj[1:1000], :T2 ; height=450) # hide

#md savefig(p2, "../assets/tut-5-phantom-subset.html") # hide
#jl display(p2)

#md # ```@raw html
#md # <center><object type="text/html" data="../../assets/tut-5-phantom-subset.html" style="width:85%; height:470px;"></object></center>
#md # ```

# ### Combination of Phantoms

# In the same way, we can add two or more phantoms, resulting in another [`Phantom`](@ref) struct:
obj2 = pelvis_phantom2D()
obj2.motion = MotionList(Translate(0.0, 0.0, -0.5, TimeRange(0.0)))
obj_sum = obj1 + obj2
p3 = plot_phantom_map(obj_sum, :T1 ; height=450) # hide

#md savefig(p3, "../assets/tut-5-phantom-sum.html") # hide
#jl display(p3)

#md # ```@raw html
#md # <center><object type="text/html" data="../../assets/tut-5-phantom-sum.html" style="width:85%; height:470px;"></object></center>
#md # ```

# ### Scalar multiplication of a Phantom

# Finally, multiplying a phantom by a scalar multiplies its proton density (`ρ`) by that amount:
obj_mul = 3*obj
obj.ρ
#-
obj_mul.ρ

# ## Phantom Storage and Sharing
# Phantoms can be stored and shared thanks to our new [Phantom File Format](3-phantom-format.md).
6 changes: 6 additions & 0 deletions docs/src/explanation/lit-2-motion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,10 @@

using KomaMRI # hide

# ## `NoMotion` struct

# ToDo

# ## `Motion` & `MotionList`

# ToDo
40 changes: 40 additions & 0 deletions docs/src/explanation/lit-3-phantom-format.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# # Phantom File Format

# ## Introduction

# While there is already an open and fairly standardised format for MRI sequences
# such as [Pulseq](https://pulseq.github.io/index.html), this is not the case for digital phantoms.
# That's why we defined a new ''.phantom'' format, which relies on the [HDF5 standard](https://www.hdfgroup.org/solutions/hdf5/).
# HDF5 is specially designed to store large amounts of heterogeneous data and to make it readable
# and writable quickly and easily. In addition, it allows the storage of metadata.
# For all these reasons, it is the ideal file format for storing phantoms.

# ## File Format Specification

# ### Phantom File Tree

#md # ```@raw html
#md <p><img class="docs-light-only" width="80%" src="assets/ph-phantom-file-format-light.svg"/></p>
#md <p><img class="docs-dark-only" width="80%" src="assets/ph-phantom-file-format-dark.svg"/></p>
# ```

# ### Action types

#md # ```@raw html
#md <p><img class="docs-light-only" width="80%" src="assets/ph-action-types-light.svg"/></p>
#md <p><img class="docs-dark-only" width="80%" src="assets/ph-action-types-dark.svg"/></p>
# ```

# ### TimeSpan types

#md # ```@raw html
#md <p><img class="docs-light-only" width="80%" src="assets/ph-timespan-types-light.svg"/></p>
#md <p><img class="docs-dark-only" width="80%" src="assets/ph-timespan-types-dark.svg"/></p>
# ```

# ### SpinSpan types

#md # ```@raw html
#md <p><img class="docs-light-only" width="80%" src="assets/ph-spinspan-types-light.svg"/></p>
#md <p><img class="docs-dark-only" width="80%" src="assets/ph-spinspan-types-dark.svg"/></p>
# ```
2 changes: 1 addition & 1 deletion docs/src/how-to/1-getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Then press `Ctrl+C` or `backspace` to return to the `julia>` prompt.
---
## My First MRI Simulation

For our first simulation we will use **KomaMRI**'s graphical user interface (GUI). For this, you will first need to load **KomaMRI** by typing `using KomaMRI`, and then launch the GUI with the [`KomaUI`](@ref) function. Note that if you want to run simulations on the GPU (for example, using CUDA), then `using CUDA` is also necessary (see [GPU Parallelization](../explanation/4-gpu-explanation.md)).
For our first simulation we will use **KomaMRI**'s graphical user interface (GUI). For this, you will first need to load **KomaMRI** by typing `using KomaMRI`, and then launch the GUI with the [`KomaUI`](@ref) function. Note that if you want to run simulations on the GPU (for example, using CUDA), then `using CUDA` is also necessary (see [GPU Parallelization](../explanation/7-gpu-explanation.md)).

```julia-repl
julia> using KomaMRI, CUDA
Expand Down
12 changes: 7 additions & 5 deletions docs/src/how-to/2-3-use-koma-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ Scanner

The Phantom struct created in this example represents a slice of a brain. To create it, we use the function `brain_phantom2D`, which is part of the subdependency **KomaMRICore**. While **KomaMRI** provides some phantom examples for experimentation, you may also want to create your custom **Phantom** struct tailored to your specific requirements.

The **Phantom** struct contains MRI parameters related to the magnetization properties of an object. These parameters include magnetization positions, proton density, relaxation times, off-resonance, among others. To view all the keys and values of the object, you can do so in the **Julia REPL** as follows:
The **Phantom** struct contains MRI parameters related to the magnetization properties of an object. These parameters include magnetization positions, proton density, relaxation times, off-resonance, among others.
For more information about Koma's Phantom and what it can do, as well as how to store and share it, check out the [Phantom](../explanation/1-phantom.md) section.
To view all the keys and values of the object, you can do so in the **Julia REPL** as follows:
```julia-repl
julia> obj
Phantom{Float64}
Expand All @@ -99,11 +101,11 @@ Phantom{Float64}
Dλ1: Array{Float64}((6506,)) [0.0, 0.0, … 0.0, 0.0]
Dλ2: Array{Float64}((6506,)) [0.0, 0.0, … 0.0, 0.0]
Dθ: Array{Float64}((6506,)) [0.0, 0.0, … 0.0, 0.0]
motion: NoMotion{Float64} NoMotion{Float64}()
...
```
As you can see, attributes of the **Phantom** struct are vectors representing object properties, with each element holding a value associated with a single magnetization.

You can also visualize the **Phantom** struct using the [`plot_phantom_map`](@ref) function, which is part of the **KomaMRIPlots** subdependency. This function plots the magnitude of a property for each magnetization at a specific spatial position. You can observe properties such as proton density and relaxation times, so feel free to replace the `` symbol with another property of the phantom in the example below:
You can also visualize the **Phantom** struct using the [`plot_phantom_map`](@ref) function:
```julia-repl
julia> plot_phantom_map(obj, :ρ)
```
Expand All @@ -126,7 +128,7 @@ julia> plot_phantom_map(sphere, :T2)

The **Sequence** struct in the example represents one of the most basic MRI sequences. It excites the object with a 90° RF pulse and then uses EPI gradients to fill the k-space in a "square" manner. While you may want to create your sequences for experiments, you can always use some of the examples already available in **KomaMRI**.

In MRI, the sequence must be carefully designed with precise timing to obtain an image. It includes subcomponents such as gradients, radio-frequency excitation signals, and sample acquisition. For more information on constructing a **Sequence** struct, refer to the [Sequence](../explanation/1-sequence.md) section.
In MRI, the sequence must be carefully designed with precise timing to obtain an image. It includes subcomponents such as gradients, radio-frequency excitation signals, and sample acquisition. For more information on constructing a **Sequence** struct, refer to the [Sequence](../explanation/4-sequence.md) section.

You can view general information about a **Sequence** struct by displaying it in the **Julia REPL**:
```julia-repl
Expand Down Expand Up @@ -191,7 +193,7 @@ Dict{String, Any} with 9 entries:
"Δt_rf" => 5.0e-5
```

All of these parameters deserve special attention. We will explain some of the most important ones here. For instance, `"Δt"` and `"Δt_rf"` represent the raster times for the gradients and RFs. `"return_type"` specifies the type of variable returned by the simulator (by default, it returns an object ready for use with **MRIReco** for reconstruction, but you can use the value `"mat"` to return a simple vector). `"gpu"` indicates whether you want to use your GPU device for simulations, and `"precision"` sets the floating-point precision. For more details on how to set these parameters, please refer to the [Simulation Parameters Section](../explanation/3-simulation.md).
All of these parameters deserve special attention. We will explain some of the most important ones here. For instance, `"Δt"` and `"Δt_rf"` represent the raster times for the gradients and RFs. `"return_type"` specifies the type of variable returned by the simulator (by default, it returns an object ready for use with **MRIReco** for reconstruction, but you can use the value `"mat"` to return a simple vector). `"gpu"` indicates whether you want to use your GPU device for simulations, and `"precision"` sets the floating-point precision. For more details on how to set these parameters, please refer to the [Simulation Parameters Section](../explanation/6-simulation.md).


### Raw Signal
Expand Down
Loading

0 comments on commit 38b96de

Please sign in to comment.