From f1aa8a439ffceb7188dc7be4b97fcd48723d5369 Mon Sep 17 00:00:00 2001
From: Pablo Villacorta Aylagas
Date: Wed, 9 Oct 2024 14:14:44 +0200
Subject: [PATCH 1/8] First commit
---
KomaMRIPlots/src/ui/DisplayFunctions.jl | 2 +-
.../{1-sequence.md => 3-sequence.md} | 2 +-
.../{2-seq-events.md => 4-seq-events.md} | 0
.../{3-simulation.md => 5-simulation.md} | 2 +-
...pu-explanation.md => 6-gpu-explanation.md} | 0
docs/src/explanation/lit-1-phantom.jl | 50 +++++++++++++++++++
docs/src/explanation/lit-2-motion.jl | 1 +
7 files changed, 54 insertions(+), 3 deletions(-)
rename docs/src/explanation/{1-sequence.md => 3-sequence.md} (99%)
rename docs/src/explanation/{2-seq-events.md => 4-seq-events.md} (100%)
rename docs/src/explanation/{3-simulation.md => 5-simulation.md} (99%)
rename docs/src/explanation/{4-gpu-explanation.md => 6-gpu-explanation.md} (100%)
create mode 100644 docs/src/explanation/lit-1-phantom.jl
create mode 100644 docs/src/explanation/lit-2-motion.jl
diff --git a/KomaMRIPlots/src/ui/DisplayFunctions.jl b/KomaMRIPlots/src/ui/DisplayFunctions.jl
index 81e0bb198..d2300efdd 100644
--- a/KomaMRIPlots/src/ui/DisplayFunctions.jl
+++ b/KomaMRIPlots/src/ui/DisplayFunctions.jl
@@ -1244,7 +1244,7 @@ function plot_phantom_map(
)
for (i, t0) in enumerate(t)
],
- currentvalue_prefix="x = ",
+ currentvalue_prefix="t = ",
currentvalue_suffix="ms",
)]
l[:margin] = attr(t=50, l=0, r=0)
diff --git a/docs/src/explanation/1-sequence.md b/docs/src/explanation/3-sequence.md
similarity index 99%
rename from docs/src/explanation/1-sequence.md
rename to docs/src/explanation/3-sequence.md
index 6f5206e7f..21aa0b50a 100644
--- a/docs/src/explanation/1-sequence.md
+++ b/docs/src/explanation/3-sequence.md
@@ -2,7 +2,7 @@
This section delves into some details about how a sequence is constructed. The sequence definition in **KomaMRI** is strongly related to the [Pulseq](https://pulseq.github.io/index.html) definition. After reading this section, you should be able to create your own **Sequence** structs for conducting custom simulations using the **KomaMRI** package.
-## Sequence Overview
+## KomaMRI Sequence Overview
Let's introduce the following simple sequence figure to expand from a visual example to a more general sequence definition:
```@raw html
diff --git a/docs/src/explanation/2-seq-events.md b/docs/src/explanation/4-seq-events.md
similarity index 100%
rename from docs/src/explanation/2-seq-events.md
rename to docs/src/explanation/4-seq-events.md
diff --git a/docs/src/explanation/3-simulation.md b/docs/src/explanation/5-simulation.md
similarity index 99%
rename from docs/src/explanation/3-simulation.md
rename to docs/src/explanation/5-simulation.md
index 5810e8a35..d64f6b4e8 100644
--- a/docs/src/explanation/3-simulation.md
+++ b/docs/src/explanation/5-simulation.md
@@ -24,7 +24,7 @@ From the programming perspective, it is needed to call the [`simulate`](@ref) fu
| `"gpu"` | is a boolean that determines whether to use GPU or CPU hardware resources, as long as they are available on the host computer. |
| `"gpu_device"` | sets the index ID of the available GPU in the host computer. |
-For instance, if you want to perform a simulation on the CPU with float64 precision using the `BlochDict()` method (assuming you have already defined `obj` and `seq`), you can do so like this:
+For instance, if you want to perform a simulation on the CPU with float64 precision using the `BlochDict()` method (assuming you have already defined `obj`, `seq` and `sys`), you can do so like this:
```julia
# Set non-default simulation parameters and run simulation
sim_params = KomaMRICore.default_sim_params()
diff --git a/docs/src/explanation/4-gpu-explanation.md b/docs/src/explanation/6-gpu-explanation.md
similarity index 100%
rename from docs/src/explanation/4-gpu-explanation.md
rename to docs/src/explanation/6-gpu-explanation.md
diff --git a/docs/src/explanation/lit-1-phantom.jl b/docs/src/explanation/lit-1-phantom.jl
new file mode 100644
index 000000000..045a828ed
--- /dev/null
+++ b/docs/src/explanation/lit-1-phantom.jl
@@ -0,0 +1,50 @@
+# # Phantom
+
+using KomaMRIBase # hide
+using PlotlyJS # 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.
+
+# ## 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.
+
+# 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
+
+# **KomaMRI** relies on the [`Phantom`](@ref) struct to define its digital phantom:
+# ```julia
+# @with_kw mutable struct Phantom{T<:Real}
+# name::String = "spins"
+# x::AbstractVector{T}
+# y::AbstractVector{T} = zeros(eltype(x), size(x))
+# z::AbstractVector{T} = zeros(eltype(x), size(x))
+# ρ::AbstractVector{T} = ones(eltype(x), size(x))
+# T1::AbstractVector{T} = ones(eltype(x), size(x)) * 1_000_000
+# T2::AbstractVector{T} = ones(eltype(x), size(x)) * 1_000_000
+# T2s::AbstractVector{T} = ones(eltype(x), size(x)) * 1_000_000
+# #Off-resonance related
+# Δw::AbstractVector{T} = zeros(eltype(x), size(x))
+# #Diffusion
+# Dλ1::AbstractVector{T} = zeros(eltype(x), size(x))
+# Dλ2::AbstractVector{T} = zeros(eltype(x), size(x))
+# Dθ::AbstractVector{T} = zeros(eltype(x), size(x))
+# #Motion
+# motion::AbstractMotion{T} = NoMotion{eltype(x)}()
+# end
+# ```
+
+## Phantom File Format
\ No newline at end of file
diff --git a/docs/src/explanation/lit-2-motion.jl b/docs/src/explanation/lit-2-motion.jl
new file mode 100644
index 000000000..e289ab73c
--- /dev/null
+++ b/docs/src/explanation/lit-2-motion.jl
@@ -0,0 +1 @@
+# # Motion
\ No newline at end of file
From 64c02fa5363e63a95d8067f6e9c511c9f4402329 Mon Sep 17 00:00:00 2001
From: Pablo Villacorta Aylagas
Date: Wed, 9 Oct 2024 23:47:00 +0200
Subject: [PATCH 2/8] Commit of the following: - Solve MotionList(rot) bug -
Pass Docs CI - Add useful constructors to `Motion`
---
KomaMRIBase/src/motion/motionlist/Motion.jl | 14 ++++++++++++++
KomaMRIBase/src/motion/motionlist/MotionList.jl | 2 +-
docs/src/explanation/lit-1-phantom.jl | 3 +--
docs/src/explanation/lit-2-motion.jl | 6 +++++-
4 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/KomaMRIBase/src/motion/motionlist/Motion.jl b/KomaMRIBase/src/motion/motionlist/Motion.jl
index d035b562b..869d0e06c 100644
--- a/KomaMRIBase/src/motion/motionlist/Motion.jl
+++ b/KomaMRIBase/src/motion/motionlist/Motion.jl
@@ -32,6 +32,20 @@ julia> motion = Motion(
spins ::AbstractSpinSpan = AllSpins()
end
+# Main constructors
+function Motion(action)
+ T = first(typeof(action).parameters)
+ return Motion(action, TimeRange(zero(T)), AllSpins())
+end
+function Motion(action, time::AbstractTimeSpan)
+ T = first(typeof(action).parameters)
+ return Motion(action, time, AllSpins())
+end
+function Motion(action, spins::AbstractSpinSpan)
+ T = first(typeof(action).parameters)
+ return Motion(action, TimeRange(zero(T)), spins)
+end
+
# Custom constructors
"""
translate = Translate(dx, dy, dz, time, spins)
diff --git a/KomaMRIBase/src/motion/motionlist/MotionList.jl b/KomaMRIBase/src/motion/motionlist/MotionList.jl
index 75e6460a2..b75841f7c 100644
--- a/KomaMRIBase/src/motion/motionlist/MotionList.jl
+++ b/KomaMRIBase/src/motion/motionlist/MotionList.jl
@@ -32,7 +32,7 @@ struct MotionList{T<:Real} <: AbstractMotion{T}
end
""" Constructors """
-MotionList(motions...) = length([motions]) > 0 ? MotionList([motions...]) : @error "You must provide at least one motion as input argument. If you do not want to define motion, use `NoMotion{T}()`"
+MotionList(motions::Motion...) = length([motions]) > 0 ? MotionList([motions...]) : @error "You must provide at least one motion as input argument. If you do not want to define motion, use `NoMotion{T}()`"
""" MotionList sub-group """
function Base.getindex(mv::MotionList{T}, p) where {T<:Real}
diff --git a/docs/src/explanation/lit-1-phantom.jl b/docs/src/explanation/lit-1-phantom.jl
index 045a828ed..86ec89de9 100644
--- a/docs/src/explanation/lit-1-phantom.jl
+++ b/docs/src/explanation/lit-1-phantom.jl
@@ -1,7 +1,6 @@
# # Phantom
-using KomaMRIBase # hide
-using PlotlyJS # hide
+using KomaMRI # hide
# The first input argument that **KomaMRI** needs for simulating is the phantom.
diff --git a/docs/src/explanation/lit-2-motion.jl b/docs/src/explanation/lit-2-motion.jl
index e289ab73c..428dea955 100644
--- a/docs/src/explanation/lit-2-motion.jl
+++ b/docs/src/explanation/lit-2-motion.jl
@@ -1 +1,5 @@
-# # Motion
\ No newline at end of file
+# # Motion
+
+using KomaMRI # hide
+
+# ToDo
\ No newline at end of file
From 38b96de38945a2c0ab93349988273c0b0fbe6977 Mon Sep 17 00:00:00 2001
From: Pablo Villacorta Aylagas
Date: Fri, 11 Oct 2024 11:04:44 +0200
Subject: [PATCH 3/8] Commit of the following: - Finish lit-1-phantom.jl - New
lit-3-phantom-format.jl - Upload svg files for phantom file tree - Update
cross references
---
README.md | 4 +-
docs/src/assets/ph-action-types-dark.svg | 824 ++++++++++++++++++
docs/src/assets/ph-action-types-light.svg | 817 +++++++++++++++++
.../assets/ph-phantom-file-format-dark.svg | 683 +++++++++++++++
.../assets/ph-phantom-file-format-light.svg | 682 +++++++++++++++
docs/src/assets/ph-spinspan-types-dark.svg | 200 +++++
docs/src/assets/ph-spinspan-types-light.svg | 198 +++++
docs/src/assets/ph-timepan-types-dark.svg | 277 ++++++
docs/src/assets/ph-timepan-types-light.svg | 277 ++++++
.../{3-sequence.md => 4-sequence.md} | 4 +-
.../{4-seq-events.md => 5-seq-events.md} | 0
.../{5-simulation.md => 6-simulation.md} | 0
...pu-explanation.md => 7-gpu-explanation.md} | 0
docs/src/explanation/lit-1-phantom.jl | 108 ++-
docs/src/explanation/lit-2-motion.jl | 6 +
docs/src/explanation/lit-3-phantom-format.jl | 40 +
docs/src/how-to/1-getting-started.md | 2 +-
docs/src/how-to/2-3-use-koma-scripts.md | 12 +-
examples/3.tutorials/lit-05-SimpleMotion.jl | 16 +-
19 files changed, 4117 insertions(+), 33 deletions(-)
create mode 100644 docs/src/assets/ph-action-types-dark.svg
create mode 100644 docs/src/assets/ph-action-types-light.svg
create mode 100644 docs/src/assets/ph-phantom-file-format-dark.svg
create mode 100644 docs/src/assets/ph-phantom-file-format-light.svg
create mode 100644 docs/src/assets/ph-spinspan-types-dark.svg
create mode 100644 docs/src/assets/ph-spinspan-types-light.svg
create mode 100644 docs/src/assets/ph-timepan-types-dark.svg
create mode 100644 docs/src/assets/ph-timepan-types-light.svg
rename docs/src/explanation/{3-sequence.md => 4-sequence.md} (96%)
rename docs/src/explanation/{4-seq-events.md => 5-seq-events.md} (100%)
rename docs/src/explanation/{5-simulation.md => 6-simulation.md} (100%)
rename docs/src/explanation/{6-gpu-explanation.md => 7-gpu-explanation.md} (100%)
create mode 100644 docs/src/explanation/lit-3-phantom-format.jl
diff --git a/README.md b/README.md
index 92bc54cde..8363b666f 100644
--- a/README.md
+++ b/README.md
@@ -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).
@@ -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:
diff --git a/docs/src/assets/ph-action-types-dark.svg b/docs/src/assets/ph-action-types-dark.svg
new file mode 100644
index 000000000..2ef49a7da
--- /dev/null
+++ b/docs/src/assets/ph-action-types-dark.svg
@@ -0,0 +1,824 @@
+
+
+
+
diff --git a/docs/src/assets/ph-action-types-light.svg b/docs/src/assets/ph-action-types-light.svg
new file mode 100644
index 000000000..9989cb360
--- /dev/null
+++ b/docs/src/assets/ph-action-types-light.svg
@@ -0,0 +1,817 @@
+
+
+
+
diff --git a/docs/src/assets/ph-phantom-file-format-dark.svg b/docs/src/assets/ph-phantom-file-format-dark.svg
new file mode 100644
index 000000000..6b2975d03
--- /dev/null
+++ b/docs/src/assets/ph-phantom-file-format-dark.svg
@@ -0,0 +1,683 @@
+
+
+
+
diff --git a/docs/src/assets/ph-phantom-file-format-light.svg b/docs/src/assets/ph-phantom-file-format-light.svg
new file mode 100644
index 000000000..6e4e26859
--- /dev/null
+++ b/docs/src/assets/ph-phantom-file-format-light.svg
@@ -0,0 +1,682 @@
+
+
+
+
diff --git a/docs/src/assets/ph-spinspan-types-dark.svg b/docs/src/assets/ph-spinspan-types-dark.svg
new file mode 100644
index 000000000..c2f081f4c
--- /dev/null
+++ b/docs/src/assets/ph-spinspan-types-dark.svg
@@ -0,0 +1,200 @@
+
+
+
+
diff --git a/docs/src/assets/ph-spinspan-types-light.svg b/docs/src/assets/ph-spinspan-types-light.svg
new file mode 100644
index 000000000..7f3839a4c
--- /dev/null
+++ b/docs/src/assets/ph-spinspan-types-light.svg
@@ -0,0 +1,198 @@
+
+
+
+
diff --git a/docs/src/assets/ph-timepan-types-dark.svg b/docs/src/assets/ph-timepan-types-dark.svg
new file mode 100644
index 000000000..fcd1709f7
--- /dev/null
+++ b/docs/src/assets/ph-timepan-types-dark.svg
@@ -0,0 +1,277 @@
+
+
+
+
diff --git a/docs/src/assets/ph-timepan-types-light.svg b/docs/src/assets/ph-timepan-types-light.svg
new file mode 100644
index 000000000..1d34ba4e2
--- /dev/null
+++ b/docs/src/assets/ph-timepan-types-light.svg
@@ -0,0 +1,277 @@
+
+
+
+
diff --git a/docs/src/explanation/3-sequence.md b/docs/src/explanation/4-sequence.md
similarity index 96%
rename from docs/src/explanation/3-sequence.md
rename to docs/src/explanation/4-sequence.md
index 21aa0b50a..d11c52617 100644
--- a/docs/src/explanation/3-sequence.md
+++ b/docs/src/explanation/4-sequence.md
@@ -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.
@@ -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 ]
diff --git a/docs/src/explanation/4-seq-events.md b/docs/src/explanation/5-seq-events.md
similarity index 100%
rename from docs/src/explanation/4-seq-events.md
rename to docs/src/explanation/5-seq-events.md
diff --git a/docs/src/explanation/5-simulation.md b/docs/src/explanation/6-simulation.md
similarity index 100%
rename from docs/src/explanation/5-simulation.md
rename to docs/src/explanation/6-simulation.md
diff --git a/docs/src/explanation/6-gpu-explanation.md b/docs/src/explanation/7-gpu-explanation.md
similarity index 100%
rename from docs/src/explanation/6-gpu-explanation.md
rename to docs/src/explanation/7-gpu-explanation.md
diff --git a/docs/src/explanation/lit-1-phantom.jl b/docs/src/explanation/lit-1-phantom.jl
index 86ec89de9..aee0c08fc 100644
--- a/docs/src/explanation/lit-1-phantom.jl
+++ b/docs/src/explanation/lit-1-phantom.jl
@@ -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"
@@ -46,4 +44,84 @@ using KomaMRI # hide
# end
# ```
-## Phantom File Format
\ No newline at end of file
+# 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 #
+#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 #
+#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 #
+#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).
\ No newline at end of file
diff --git a/docs/src/explanation/lit-2-motion.jl b/docs/src/explanation/lit-2-motion.jl
index 428dea955..62384da68 100644
--- a/docs/src/explanation/lit-2-motion.jl
+++ b/docs/src/explanation/lit-2-motion.jl
@@ -2,4 +2,10 @@
using KomaMRI # hide
+# ## `NoMotion` struct
+
+# ToDo
+
+# ## `Motion` & `MotionList`
+
# ToDo
\ No newline at end of file
diff --git a/docs/src/explanation/lit-3-phantom-format.jl b/docs/src/explanation/lit-3-phantom-format.jl
new file mode 100644
index 000000000..c24ff9ffe
--- /dev/null
+++ b/docs/src/explanation/lit-3-phantom-format.jl
@@ -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
+#md
+# ```
+
+# ### Action types
+
+#md # ```@raw html
+#md
+#md
+# ```
+
+# ### TimeSpan types
+
+#md # ```@raw html
+#md
+#md
+# ```
+
+# ### SpinSpan types
+
+#md # ```@raw html
+#md
+#md
+# ```
\ No newline at end of file
diff --git a/docs/src/how-to/1-getting-started.md b/docs/src/how-to/1-getting-started.md
index 734f0339a..8f818a281 100644
--- a/docs/src/how-to/1-getting-started.md
+++ b/docs/src/how-to/1-getting-started.md
@@ -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
diff --git a/docs/src/how-to/2-3-use-koma-scripts.md b/docs/src/how-to/2-3-use-koma-scripts.md
index 68b3ab3e2..b66f8e0fc 100644
--- a/docs/src/how-to/2-3-use-koma-scripts.md
+++ b/docs/src/how-to/2-3-use-koma-scripts.md
@@ -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}
@@ -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, :ρ)
```
@@ -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
@@ -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
diff --git a/examples/3.tutorials/lit-05-SimpleMotion.jl b/examples/3.tutorials/lit-05-SimpleMotion.jl
index d20929f62..ae1e2d29d 100644
--- a/examples/3.tutorials/lit-05-SimpleMotion.jl
+++ b/examples/3.tutorials/lit-05-SimpleMotion.jl
@@ -21,11 +21,11 @@ obj.motion = MotionList(
)
p1 = plot_phantom_map(obj, :T2 ; height=450, time_samples=4) # hide
-#md savefig(p1, "../assets/5-phantom1.html") # hide
+#md savefig(p1, "../assets/tut-5-phantom.html") # hide
#jl display(p1)
#md # ```@raw html
-#md #
+#md #
#md # ```
## Read Sequence # hide
@@ -46,12 +46,12 @@ image1 = reconstruction(acq1, reconParams) # hide
# we will observe motion-induced artifacts in the reconstructed image.
## Plotting the recon # hide
p2 = plot_image(abs.(image1[:, :, 1]); height=400) # hide
-#md savefig(p2, "../assets/5-recon1.html") # hide
+#md savefig(p2, "../assets/tut-5-recon1.html") # hide
#jl display(p2)
#md # ```@raw html
#md #