From b4f96458b54c9270f675f17ba32c788ab5632fec Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Fri, 15 Dec 2023 19:58:41 -0300 Subject: [PATCH 01/15] Fix iframe in educational example --- docs/src/pluto-simulation.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/src/pluto-simulation.md b/docs/src/pluto-simulation.md index 0e853b9c3..422ee5615 100644 --- a/docs/src/pluto-simulation.md +++ b/docs/src/pluto-simulation.md @@ -8,4 +8,7 @@ The participants used **KomaMRI** within a **Pluto** notebook to simulate some b ```@raw html - +
View Solution + +
+``` From ba7b836a443d33d4759e2a7f727cfeac37e281b3 Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Mon, 18 Dec 2023 14:34:07 -0300 Subject: [PATCH 02/15] Rename pluto folder and hide text in solution --- docs/src/pluto-simulation.md | 4 ++-- .../simulation-example-empty.html | 0 .../simulation-example-empty.jl | 0 .../simulation-example.html | 15 +++++++++++++++ .../simulation-example.jl | 0 examples/pluto/simulation-example.html | 15 --------------- 6 files changed, 17 insertions(+), 17 deletions(-) rename examples/{pluto => educational_pluto_notebook}/simulation-example-empty.html (100%) rename examples/{pluto => educational_pluto_notebook}/simulation-example-empty.jl (100%) create mode 100644 examples/educational_pluto_notebook/simulation-example.html rename examples/{pluto => educational_pluto_notebook}/simulation-example.jl (100%) delete mode 100644 examples/pluto/simulation-example.html diff --git a/docs/src/pluto-simulation.md b/docs/src/pluto-simulation.md index 422ee5615..0a6b9f4fd 100644 --- a/docs/src/pluto-simulation.md +++ b/docs/src/pluto-simulation.md @@ -7,8 +7,8 @@ This example was used in the workshop [MRI: Processing your own data](https://gi The participants used **KomaMRI** within a **Pluto** notebook to simulate some basic 1D sequences: Free Induction Decay (FID), Gradient Echo (GE), and Spin Echo (SE). Try to solve the problems yourself! 😼 ```@raw html - +
View Solution - +
``` diff --git a/examples/pluto/simulation-example-empty.html b/examples/educational_pluto_notebook/simulation-example-empty.html similarity index 100% rename from examples/pluto/simulation-example-empty.html rename to examples/educational_pluto_notebook/simulation-example-empty.html diff --git a/examples/pluto/simulation-example-empty.jl b/examples/educational_pluto_notebook/simulation-example-empty.jl similarity index 100% rename from examples/pluto/simulation-example-empty.jl rename to examples/educational_pluto_notebook/simulation-example-empty.jl diff --git a/examples/educational_pluto_notebook/simulation-example.html b/examples/educational_pluto_notebook/simulation-example.html new file mode 100644 index 000000000..c7282fae3 --- /dev/null +++ b/examples/educational_pluto_notebook/simulation-example.html @@ -0,0 +1,15 @@ + + + + + +
\ No newline at end of file diff --git a/examples/pluto/simulation-example.jl b/examples/educational_pluto_notebook/simulation-example.jl similarity index 100% rename from examples/pluto/simulation-example.jl rename to examples/educational_pluto_notebook/simulation-example.jl diff --git a/examples/pluto/simulation-example.html b/examples/pluto/simulation-example.html deleted file mode 100644 index e934e79fd..000000000 --- a/examples/pluto/simulation-example.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -
\ No newline at end of file From bc6b02f796cffa9a79a465bef5007a56ca538591 Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Mon, 18 Dec 2023 15:02:20 -0300 Subject: [PATCH 03/15] Rename pluto folder and update .jl file --- docs/src/pluto-simulation.md | 4 ++-- .../simulation-example-empty.html | 0 .../simulation-example-empty.jl | 0 .../simulation-example.html | 0 .../simulation-example.jl | 6 +++--- 5 files changed, 5 insertions(+), 5 deletions(-) rename examples/{educational_pluto_notebook => 6.educational_pluto_notebook}/simulation-example-empty.html (100%) rename examples/{educational_pluto_notebook => 6.educational_pluto_notebook}/simulation-example-empty.jl (100%) rename examples/{educational_pluto_notebook => 6.educational_pluto_notebook}/simulation-example.html (100%) rename examples/{educational_pluto_notebook => 6.educational_pluto_notebook}/simulation-example.jl (99%) diff --git a/docs/src/pluto-simulation.md b/docs/src/pluto-simulation.md index 0a6b9f4fd..044ca9305 100644 --- a/docs/src/pluto-simulation.md +++ b/docs/src/pluto-simulation.md @@ -7,8 +7,8 @@ This example was used in the workshop [MRI: Processing your own data](https://gi The participants used **KomaMRI** within a **Pluto** notebook to simulate some basic 1D sequences: Free Induction Decay (FID), Gradient Echo (GE), and Spin Echo (SE). Try to solve the problems yourself! 😼 ```@raw html - +
View Solution - +
``` diff --git a/examples/educational_pluto_notebook/simulation-example-empty.html b/examples/6.educational_pluto_notebook/simulation-example-empty.html similarity index 100% rename from examples/educational_pluto_notebook/simulation-example-empty.html rename to examples/6.educational_pluto_notebook/simulation-example-empty.html diff --git a/examples/educational_pluto_notebook/simulation-example-empty.jl b/examples/6.educational_pluto_notebook/simulation-example-empty.jl similarity index 100% rename from examples/educational_pluto_notebook/simulation-example-empty.jl rename to examples/6.educational_pluto_notebook/simulation-example-empty.jl diff --git a/examples/educational_pluto_notebook/simulation-example.html b/examples/6.educational_pluto_notebook/simulation-example.html similarity index 100% rename from examples/educational_pluto_notebook/simulation-example.html rename to examples/6.educational_pluto_notebook/simulation-example.html diff --git a/examples/educational_pluto_notebook/simulation-example.jl b/examples/6.educational_pluto_notebook/simulation-example.jl similarity index 99% rename from examples/educational_pluto_notebook/simulation-example.jl rename to examples/6.educational_pluto_notebook/simulation-example.jl index 5e04bf2a0..bdee0476c 100644 --- a/examples/educational_pluto_notebook/simulation-example.jl +++ b/examples/6.educational_pluto_notebook/simulation-example.jl @@ -165,8 +165,8 @@ begin seq_gre += gx_pre # (2.2) Append a `Sequence` block called `readout` gx = Grad(2*Ax/(2T_gx_pre), 2T_gx_pre, 0, 0) - adc_readout = ADC(100, 2T_gx_pre) - readout = Sequence([gx;;], [RF(0,0);;], [adc_readout]) + adc2 = ADC(100, 2T_gx_pre) + readout = Sequence([gx;;], [RF(0,0);;], [adc2]) seq_gre += readout end @@ -1900,7 +1900,7 @@ version = "3.0.2+0" # ╟─cc66bfed-b61b-4067-8c94-4c54b82a3b42 # ╠═3e87790c-ddec-4897-a5d8-276cf7242147 # ╠═8529f36d-2d39-4b45-a821-01c8346539fd -# ╠═6dfe338d-de85-4adb-b030-09455fae78a0 +# ╟─6dfe338d-de85-4adb-b030-09455fae78a0 # ╟─8e474add-8651-431b-b481-7a139037dbd2 # ╠═c6e33cb8-f42c-4643-9257-124d2804d3da # ╠═0266632d-5ca4-4196-a523-33a66dd70e0c From 80c480267bc3a917ea2e9fc40f6f533c72718fc9 Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Mon, 18 Dec 2023 18:24:09 -0300 Subject: [PATCH 04/15] Update pluto example --- .../simulation-example-empty.html | 4 +- .../simulation-example-empty.jl | 44 ++++++++----- .../simulation-example.html | 4 +- .../simulation-example.jl | 66 ++++++++++++------- 4 files changed, 71 insertions(+), 47 deletions(-) diff --git a/examples/6.educational_pluto_notebook/simulation-example-empty.html b/examples/6.educational_pluto_notebook/simulation-example-empty.html index 9f1ebd6fa..185802bee 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-empty.html +++ b/examples/6.educational_pluto_notebook/simulation-example-empty.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example-empty.jl b/examples/6.educational_pluto_notebook/simulation-example-empty.jl index a3185f602..bb3c4c81e 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-empty.jl +++ b/examples/6.educational_pluto_notebook/simulation-example-empty.jl @@ -116,6 +116,9 @@ Let's create a different sequence. # (2.1) Create a gradient `gx_pre`, use the variable `Ax`!! # ... +# (2.2) Append a `Sequence` block called `readout` +# ... + # ╔═╡ 8b4a1ad9-2d6a-4c8f-bb8e-f43c2d058195 # (2.3) Plot `seq_gre` and the k-space # ... @@ -162,22 +165,32 @@ $$p_{\Delta w}(w) = \frac{T_2^{'}}{\pi(1+T_2^{'2} w^2)},\quad\text{with }\frac{1 In this excercise we will simplify this distribution, but we will obtain a similar effect. - - (3.1) Create a copy of the original phantom `obj_t2star = copy(obj)` - - (3.2) Add a linear distribution of off-resonance to `obj_t2star.Δw .= 2π[-10, 10] rad/s` - - (3.3) Plot `obj_t2star` with `plot_phantom_map(obj_t2star, :Δw)` and verify it is correct +- (3.1) Create a new phantom named `obj_t2star` with spins at the same positions as the original phantom `obj`, each having a linear distribution of the off-resonance parameter. To achieve this, follow these steps: + * (3.1.1) Create an empty phantom called `obj_t2star`. + * (3.1.2) Iterate over 20 equispaced values starting from -20π up to 20π; these values represent the linear off-resonance distribution. + * (3.1.3) Within the loop, create a copy of the original phantom: `obj_aux = copy(obj)` with the off-resonance value of the current iteration. + * (3.1.4) Within the loop, update the `obj_t2star` by superimposing it with `obj_aux`. + * (3.1.5) Finally, outside the loop, divide the proton density of `obj_t2star` by 20. + + - (3.2) Plot `obj_t2star` with `plot_phantom_map(obj_t2star, :Δw)` and verify it is correct """ # ╔═╡ 9f3683c1-4dfb-419b-9e04-f93bb7f80503 # (3.1) Create a copy of the original phantom obj_t2star = copy(obj) -# ... - -# ╔═╡ ee7e81e7-484c-44a8-a191-f73e24707ce9 -# (3.2) Add a linear distribution of off-resonance -# ... + # (3.1.1) Empty phantom + # ... + # (3.1.2) Iterate over linear off-resonance distribution + # ... + # (3.1.3) Copy original phantom and modify off-resonance + # ... + # (3.1.4) Update the phantom + # ... + # (3.1.5) Divide the proton density + # ... # ╔═╡ 2ee7ba47-02e5-4b02-a162-ddbd5ed47c7b -# (3.3) Plot obj_t2star +# (3.2) Plot obj_t2star # ... # ╔═╡ 27686262-1a1e-45fa-b4ee-90ae1d9ee34e @@ -189,19 +202,19 @@ md""" """ # ╔═╡ e4ef5145-a63c-4f91-ac04-3b5bf16c0842 -# (3.4) Simulate the seq_gre sequence +# (3.3) Simulate the seq_gre sequence # ... # ╔═╡ 1a83d897-705b-443d-89a4-ea5e3e6a3c07 -# (3.5) Plot the simulated signal +# (3.4) Plot the simulated signal # ... # ╔═╡ 18c82ff1-0bde-4fa0-848c-d0eb73d1ac7c -# (3.6) Compare the plot in (3.5) with (2.6) +# (3.5) Compare the plot in (3.5) with (2.6) # ... # ╔═╡ 4a4a6bd3-b820-479c-89e3-f3ce79a316db -# (3.7) Reconstruct the 1D image +# (3.6) Reconstruct the 1D image # ... # ╔═╡ 3357a283-a234-4d15-8fdf-7fbec58b33a7 @@ -227,11 +240,9 @@ Our sequence consists of: # (4.1) A 90deg hard RF pulse # ... -# ╔═╡ ae762259-46a7-4323-bbd1-adee08a139f2 # (4.2) A `Delay` of TE/2 with a positive gradient (area `Ax`) # ... -# ╔═╡ 8968bbd1-0705-4a58-9fc8-225929ce3ac1 # (4.3) A 180deg hard RF pulse # ... @@ -1876,7 +1887,6 @@ version = "3.0.2+0" # ╠═0f96a83d-96ef-4768-9330-87c466e35c93 # ╟─97104c46-e81f-444a-957f-0bbb1b02f1b8 # ╠═9f3683c1-4dfb-419b-9e04-f93bb7f80503 -# ╠═ee7e81e7-484c-44a8-a191-f73e24707ce9 # ╠═2ee7ba47-02e5-4b02-a162-ddbd5ed47c7b # ╟─27686262-1a1e-45fa-b4ee-90ae1d9ee34e # ╠═e4ef5145-a63c-4f91-ac04-3b5bf16c0842 @@ -1885,8 +1895,6 @@ version = "3.0.2+0" # ╠═4a4a6bd3-b820-479c-89e3-f3ce79a316db # ╟─3357a283-a234-4d15-8fdf-7fbec58b33a7 # ╠═c8a37593-3028-4e50-ad07-dc81edba45c8 -# ╠═ae762259-46a7-4323-bbd1-adee08a139f2 -# ╠═8968bbd1-0705-4a58-9fc8-225929ce3ac1 # ╠═75ee6dbe-598a-47be-9655-3de3bc015281 # ╠═68d88987-3de7-42ae-9380-91ffae3ca40b # ╠═f1f3b700-5916-496f-b938-46f7f08b4eb6 diff --git a/examples/6.educational_pluto_notebook/simulation-example.html b/examples/6.educational_pluto_notebook/simulation-example.html index c7282fae3..82a6636cc 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.html +++ b/examples/6.educational_pluto_notebook/simulation-example.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example.jl b/examples/6.educational_pluto_notebook/simulation-example.jl index bdee0476c..6ba83d327 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.jl +++ b/examples/6.educational_pluto_notebook/simulation-example.jl @@ -184,11 +184,11 @@ raw_gre = simulate(obj, seq_gre, sys) # ╔═╡ 41d14dec-b852-4316-aefb-c3d08fa43216 # (2.6) Plot the simulated signal -plot_signal(raw_gre; slider=false) +signal_gre = plot_signal(raw_gre; slider=false) # ╔═╡ 9a88a54b-bcc7-41ad-8e60-f4d450dccb2d # (2.7) Reconstruct the 1D image -plot(abs.(KomaMRI.fftc(raw_gre.profiles[1].data))) +recon_gre = plot(abs.(KomaMRI.fftc(raw_gre.profiles[1].data))) # ╔═╡ 97104c46-e81f-444a-957f-0bbb1b02f1b8 md""" @@ -204,51 +204,67 @@ $$p_{\Delta w}(w) = \frac{T_2^{'}}{\pi(1+T_2^{'2} w^2)},\quad\text{with }\frac{1 In this excercise we will simplify this distribution, but we will obtain a similar effect. - - (3.1) Create a copy of the original phantom `obj_t2star = copy(obj)` - - (3.2) Add a linear distribution of off-resonance to `obj_t2star.Δw .= 2π[-10, 10] rad/s` - - (3.3) Plot `obj_t2star` with `plot_phantom_map(obj_t2star, :Δw)` and verify it is correct +- (3.1) Create a new phantom named `obj_t2star` with spins at the same positions as the original phantom `obj`, each having a linear distribution of the off-resonance parameter. To achieve this, follow these steps: + * (3.1.1) Create an empty phantom called `obj_t2star`. + * (3.1.2) Iterate over 20 equispaced values starting from -20π up to 20π; these values represent the linear off-resonance distribution. + * (3.1.3) Within the loop, create a copy of the original phantom: `obj_aux = copy(obj)` with the off-resonance value of the current iteration. + * (3.1.4) Within the loop, update the `obj_t2star` by superimposing it with `obj_aux`. + * (3.1.5) Finally, outside the loop, divide the proton density of `obj_t2star` by 20. + + - (3.2) Plot `obj_t2star` with `plot_phantom_map(obj_t2star, :Δw)` and verify it is correct """ # ╔═╡ ee7e81e7-484c-44a8-a191-f73e24707ce9 +# (3.1) Create the obj_t2star phantom begin -# (3.1) Create a copy of the original phantom obj_t2star = copy(obj) - obj_t2star = copy(obj) -# (3.2) Add a linear distribution of off-resonance - obj_t2star.Δw .= 2π*collect(range(-50, 50, 20)) - obj_t2star + # (3.1.1) Empty phantom + obj_t2star = Phantom{Float64}(x=[]) + # (3.1.2) Iterate over linear off-resonance distribution + linear_offresonance_distribution = 2π .* range(-10, 10, 20) + for off = linear_offresonance_distribution + # (3.1.3) Copy original phantom and modify off-resonance + aux = copy(obj) + aux.Δw .= off + aux.y .+= off * 1e-6 # So the distribution is visible + # (3.1.4) Update the phantom + obj_t2star += aux + end + # (3.1.5) Divide the proton density + obj_t2star.ρ .= 1.0 / 20.0 + obj_t2star.name = "T2 star phantom" # Change the name of the phantom end # ╔═╡ 2ee7ba47-02e5-4b02-a162-ddbd5ed47c7b -# (3.3) Plot obj_t2star +# (3.2) Plot obj_t2star plot_phantom_map(obj_t2star, :Δw) # ╔═╡ 27686262-1a1e-45fa-b4ee-90ae1d9ee34e md""" - - (3.4) Simulate the `seq_gre` sequence - - (3.5) Plot the simulated signal - - (3.6) Compare the plot in (3.5) with (2.6) - - (3.7) Reconstruct the 1D image + - (3.3) Simulate the `seq_gre` sequence + - (3.4) Plot the simulated signal + - (3.5) Compare the plot in (3.5) with (2.6) + - (3.6) Reconstruct the 1D image """ # ╔═╡ e4ef5145-a63c-4f91-ac04-3b5bf16c0842 -# (3.4) Simulate the seq_gre sequence +# (3.3) Simulate the seq_gre sequence raw_t2_star_gre = simulate(obj_t2star, seq_gre, sys) # ╔═╡ 1a83d897-705b-443d-89a4-ea5e3e6a3c07 -# (3.5) Plot the simulated signal -plot_signal(raw_t2_star_gre; slider=false) +# (3.4) Plot the simulated signal +signal_t2_star_gre = plot_signal(raw_t2_star_gre; slider=false) # ╔═╡ 18c82ff1-0bde-4fa0-848c-d0eb73d1ac7c -# (3.6) Compare the plot in (3.5) with (2.6) -plot_signal(raw_gre; slider=false) +# (3.5) Compare the plot in (3.5) with (2.6) +[signal_gre; signal_t2_star_gre] # ╔═╡ 4a4a6bd3-b820-479c-89e3-f3ce79a316db -# (3.7) Reconstruct the 1D image -plot(abs.(KomaMRI.fftc(raw_t2_star_gre.profiles[1].data))) +# (3.6) Reconstruct the 1D image +recon_t2_star_gre = plot(abs.(KomaMRI.fftc(raw_t2_star_gre.profiles[1].data))) # ╔═╡ f2d388d5-4cda-4a0b-be50-ea2cdc283692 -plot(abs.(KomaMRI.fftc(raw_gre.profiles[1].data))) +[recon_gre recon_t2_star_gre] # ╔═╡ 3357a283-a234-4d15-8fdf-7fbec58b33a7 md""" @@ -308,10 +324,10 @@ raw_t2_star_se = simulate(obj_t2star, seq_se, sys) # ╔═╡ 2e65ae31-f50a-462b-9744-80bf6cdb388e # (4.9) Reconstruct the 1D image -plot(abs.(KomaMRI.fftc(raw_t2_star_se.profiles[1].data))) +recon_t2_star_se = plot(abs.(KomaMRI.fftc(raw_t2_star_se.profiles[1].data))) # ╔═╡ 34824db7-13c4-45e2-befa-f027b9b585c0 -plot(abs.(KomaMRI.fftc(raw_t2_star_gre.profiles[1].data))) +[recon_t2_star_se recon_t2_star_gre recon_gre] # ╔═╡ fe8bbcd2-e8f5-4225-80c3-47e73176fb3d md""" From 3c096ab2c89d4014f3587cf34096b73bf5673e2d Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Tue, 19 Dec 2023 09:04:21 -0300 Subject: [PATCH 05/15] Rename and update pluto example files --- docs/src/pluto-simulation.md | 4 +- .../simulation-example-empty.html | 15 -- .../simulation-example-solution.html | 15 ++ ...mpty.jl => simulation-example-solution.jl} | 195 +++++++++++------ .../simulation-example.html | 4 +- .../simulation-example.jl | 205 +++++++----------- 6 files changed, 219 insertions(+), 219 deletions(-) delete mode 100644 examples/6.educational_pluto_notebook/simulation-example-empty.html create mode 100644 examples/6.educational_pluto_notebook/simulation-example-solution.html rename examples/6.educational_pluto_notebook/{simulation-example-empty.jl => simulation-example-solution.jl} (94%) diff --git a/docs/src/pluto-simulation.md b/docs/src/pluto-simulation.md index 044ca9305..16ee7f036 100644 --- a/docs/src/pluto-simulation.md +++ b/docs/src/pluto-simulation.md @@ -7,8 +7,8 @@ This example was used in the workshop [MRI: Processing your own data](https://gi The participants used **KomaMRI** within a **Pluto** notebook to simulate some basic 1D sequences: Free Induction Decay (FID), Gradient Echo (GE), and Spin Echo (SE). Try to solve the problems yourself! 😼 ```@raw html - -
View Solution +
View Solution +
``` diff --git a/examples/6.educational_pluto_notebook/simulation-example-empty.html b/examples/6.educational_pluto_notebook/simulation-example-empty.html deleted file mode 100644 index 185802bee..000000000 --- a/examples/6.educational_pluto_notebook/simulation-example-empty.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - -
\ No newline at end of file diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.html b/examples/6.educational_pluto_notebook/simulation-example-solution.html new file mode 100644 index 000000000..82a6636cc --- /dev/null +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.html @@ -0,0 +1,15 @@ + + + + + +
\ No newline at end of file diff --git a/examples/6.educational_pluto_notebook/simulation-example-empty.jl b/examples/6.educational_pluto_notebook/simulation-example-solution.jl similarity index 94% rename from examples/6.educational_pluto_notebook/simulation-example-empty.jl rename to examples/6.educational_pluto_notebook/simulation-example-solution.jl index bb3c4c81e..6ba83d327 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-empty.jl +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.jl @@ -4,6 +4,16 @@ using Markdown using InteractiveUtils +# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). +macro bind(def, element) + quote + local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end + local el = $(esc(element)) + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) + el + end +end + # ╔═╡ 3e87790c-ddec-4897-a5d8-276cf7242147 begin using Pkg @@ -43,15 +53,24 @@ For the hardware limits use the default scanner `sys = Scanner()`. # ╔═╡ c6e33cb8-f42c-4643-9257-124d2804d3da # (1.1) A 90-deg block RF pulse -# ... +begin + sys = Scanner() + durRF = π/2/(2π*γ*sys.B1); #90-degree hard excitation pulse + rf = PulseDesigner.RF_hard(sys.B1, durRF, sys) +end # ╔═╡ 0266632d-5ca4-4196-a523-33a66dd70e0c # (1.2) An ADC to capture the signal -# ... +adc = ADC(100, 50e-3) # ╔═╡ 0975547d-67d9-4e6b-88ff-a9dd06a7f9ef # (1.3) Plot the generated Sequence -# ... +begin + seq = Sequence() + seq += rf + seq += adc + plot_seq(seq; slider=false) +end # ╔═╡ f11a2fa2-eff9-4979-b739-3da2b24a9a45 md""" @@ -66,11 +85,17 @@ Generate a virtual object: # ╔═╡ d16efa62-dce7-4ec3-9e3c-b5e1677377fc # (1.4) A Phantom with 20 spins -# ... +begin + obj = Phantom(x=collect(range(-1e-3,1e-3,20))) + obj.ρ .= 1 + obj.T1 .= 500e-3 + obj.T2 .= 50e-3 + obj +end # ╔═╡ 35ff3402-dc36-4b91-bec9-b4d21faf3e68 # (1.5) Plot the generated Phantom -# ... +plot_phantom_map(obj, :T1) # ╔═╡ ea542271-01c2-4962-a708-804b23a861b9 md""" @@ -81,15 +106,21 @@ md""" # ╔═╡ c47a50b8-c930-4c96-9b34-2772186634d9 # (1.6) Finally, use the generated seq, obj, and sys to simulate the FID -# ... +raw = simulate(obj, seq, sys) # ╔═╡ 7a66ab47-918f-4582-895f-1b4690562051 # (1.7) Plot the resulting raw data with plot_signal -# ... +plot_signal(raw; slider=false) # ╔═╡ 1231b832-47b1-4ccb-9b56-a67838598cc7 # (1.8) Is the signal the same as `plot(t, exp.(-t ./ T2))`? -# ... +begin + t = range(0, 50, 100) + plot( + scatter(x=t, y=20.0.*exp.(-t ./ 50)), + Layout(yaxis_range=[0, 20.1]) + ) +end # ╔═╡ e4c80c24-20fd-42e5-9dcd-a65958569c01 md""" @@ -112,44 +143,52 @@ Let's create a different sequence. - (2.4) Plot the $$k$$-space with the `plot_kspace` function """ +# ╔═╡ 74666c1a-2673-4936-982b-6229bf92af66 +md""" + - (2.5) Simulate the `seq_gre` sequence + - (2.6) Plot the simulated signal + - (2.7) Reconstruct the 1D image + - (2.8) Do you notice anything weird? If the answer is yes, try adjusting `Ax` to change the `FOV` of the acquisition +""" + +# ╔═╡ 0f96a83d-96ef-4768-9330-87c466e35c93 +# (2.8) Do you notice anything weird? Change Ax! +@bind Ax Slider(range(0, 20, 20)*1e-5, default=10e-5) # Gradient's area in [T/m s] + # ╔═╡ 9179aa40-bb40-4a36-ae1e-00ae42935a5f # (2.1) Create a gradient `gx_pre`, use the variable `Ax`!! -# ... - +begin + T_gx_pre = 10e-3 + gx_pre = Grad(-Ax/T_gx_pre, T_gx_pre, 0, 0) + seq_gre = Sequence() + seq_gre += rf + seq_gre += gx_pre # (2.2) Append a `Sequence` block called `readout` -# ... + gx = Grad(2*Ax/(2T_gx_pre), 2T_gx_pre, 0, 0) + adc2 = ADC(100, 2T_gx_pre) + readout = Sequence([gx;;], [RF(0,0);;], [adc2]) + seq_gre += readout +end # ╔═╡ 8b4a1ad9-2d6a-4c8f-bb8e-f43c2d058195 # (2.3) Plot `seq_gre` and the k-space -# ... +plot_seq(seq_gre; slider=false) # ╔═╡ 3abca406-2e6b-4b37-8835-65cfad9d0caa # (2.4) Plot the $k$-space with the `plot_kspace` function -# ... - -# ╔═╡ 74666c1a-2673-4936-982b-6229bf92af66 -md""" - - (2.5) Simulate the `seq_gre` sequence - - (2.6) Plot the simulated signal - - (2.7) Reconstruct the 1D image - - (2.8) Do you notice anything weird? If the answer is yes, try adjusting `Ax` to change the `FOV` of the acquisition -""" +plot_kspace(seq_gre) # ╔═╡ ada602d2-4f4b-4fb4-a763-8a639e05ff38 # (2.5) Simulate the seq_gre sequence -# ... +raw_gre = simulate(obj, seq_gre, sys) # ╔═╡ 41d14dec-b852-4316-aefb-c3d08fa43216 # (2.6) Plot the simulated signal -# ... +signal_gre = plot_signal(raw_gre; slider=false) # ╔═╡ 9a88a54b-bcc7-41ad-8e60-f4d450dccb2d # (2.7) Reconstruct the 1D image -# ... - -# ╔═╡ 0f96a83d-96ef-4768-9330-87c466e35c93 -# (2.8) Do you notice anything weird? Change Ax! -# ... +recon_gre = plot(abs.(KomaMRI.fftc(raw_gre.profiles[1].data))) # ╔═╡ 97104c46-e81f-444a-957f-0bbb1b02f1b8 md""" @@ -176,46 +215,56 @@ In this excercise we will simplify this distribution, but we will obtain a simil """ -# ╔═╡ 9f3683c1-4dfb-419b-9e04-f93bb7f80503 -# (3.1) Create a copy of the original phantom obj_t2star = copy(obj) - # (3.1.1) Empty phantom - # ... - # (3.1.2) Iterate over linear off-resonance distribution - # ... - # (3.1.3) Copy original phantom and modify off-resonance - # ... - # (3.1.4) Update the phantom - # ... - # (3.1.5) Divide the proton density - # ... +# ╔═╡ ee7e81e7-484c-44a8-a191-f73e24707ce9 +# (3.1) Create the obj_t2star phantom +begin + # (3.1.1) Empty phantom + obj_t2star = Phantom{Float64}(x=[]) + # (3.1.2) Iterate over linear off-resonance distribution + linear_offresonance_distribution = 2π .* range(-10, 10, 20) + for off = linear_offresonance_distribution + # (3.1.3) Copy original phantom and modify off-resonance + aux = copy(obj) + aux.Δw .= off + aux.y .+= off * 1e-6 # So the distribution is visible + # (3.1.4) Update the phantom + obj_t2star += aux + end + # (3.1.5) Divide the proton density + obj_t2star.ρ .= 1.0 / 20.0 + obj_t2star.name = "T2 star phantom" # Change the name of the phantom +end # ╔═╡ 2ee7ba47-02e5-4b02-a162-ddbd5ed47c7b # (3.2) Plot obj_t2star -# ... +plot_phantom_map(obj_t2star, :Δw) # ╔═╡ 27686262-1a1e-45fa-b4ee-90ae1d9ee34e md""" - - (3.4) Simulate the `seq_gre` sequence - - (3.5) Plot the simulated signal - - (3.6) Compare the plot in (3.5) with (2.6) - - (3.7) Reconstruct the 1D image + - (3.3) Simulate the `seq_gre` sequence + - (3.4) Plot the simulated signal + - (3.5) Compare the plot in (3.5) with (2.6) + - (3.6) Reconstruct the 1D image """ # ╔═╡ e4ef5145-a63c-4f91-ac04-3b5bf16c0842 # (3.3) Simulate the seq_gre sequence -# ... +raw_t2_star_gre = simulate(obj_t2star, seq_gre, sys) # ╔═╡ 1a83d897-705b-443d-89a4-ea5e3e6a3c07 # (3.4) Plot the simulated signal -# ... +signal_t2_star_gre = plot_signal(raw_t2_star_gre; slider=false) # ╔═╡ 18c82ff1-0bde-4fa0-848c-d0eb73d1ac7c # (3.5) Compare the plot in (3.5) with (2.6) -# ... +[signal_gre; signal_t2_star_gre] # ╔═╡ 4a4a6bd3-b820-479c-89e3-f3ce79a316db # (3.6) Reconstruct the 1D image -# ... +recon_t2_star_gre = plot(abs.(KomaMRI.fftc(raw_t2_star_gre.profiles[1].data))) + +# ╔═╡ f2d388d5-4cda-4a0b-be50-ea2cdc283692 +[recon_gre recon_t2_star_gre] # ╔═╡ 3357a283-a234-4d15-8fdf-7fbec58b33a7 md""" @@ -236,27 +285,24 @@ Our sequence consists of: - (4.6) Plot `seq_se` and its k-space. Is the k-space the same as `seq_gre` in (2.3)? """ -# ╔═╡ c8a37593-3028-4e50-ad07-dc81edba45c8 +# ╔═╡ 27e65680-22a0-4079-b6df-d60a3218e52e # (4.1) A 90deg hard RF pulse -# ... - +begin + seq_se = Sequence() + seq_se += rf # (4.2) A `Delay` of TE/2 with a positive gradient (area `Ax`) -# ... - + seq_se += -1*gx_pre + seq_se += (0.0+2.0im)*rf # (4.3) A 180deg hard RF pulse -# ... - -# ╔═╡ 75ee6dbe-598a-47be-9655-3de3bc015281 -# (4.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in TE -# ... - -# ╔═╡ 68d88987-3de7-42ae-9380-91ffae3ca40b -# (4.5) Create concatenating these blocks into a sequence called `seq_se` -# ... + seq_se += readout +end # ╔═╡ f1f3b700-5916-496f-b938-46f7f08b4eb6 # (4.6) Plot seq_se and its k-space. Is the k-space the same as seq_gre in (2.3)? -# ... +plot_seq(seq_se; slider=false) + +# ╔═╡ 4e1434e1-673f-4206-a271-9edec10ebd6a +plot_kspace(seq_se) # ╔═╡ 45952512-aaf1-43d8-a95e-c32bb2633f42 md""" @@ -267,15 +313,21 @@ md""" # ╔═╡ 97479437-9ce3-4b33-9134-0f2af89bccb5 # (4.7) Simulate using seq_se and obj_t2star -# ... +raw_t2_star_se = simulate(obj_t2star, seq_se, sys) # ╔═╡ 1c79b37e-d4e0-490f-9466-20ce28f017ae # (4.8) Compare the signal obtained in (4.6) with the one at (3.5) -# ... +[ + plot_signal(raw_t2_star_se; slider=false); + plot_signal(raw_t2_star_gre; slider=false) +] # ╔═╡ 2e65ae31-f50a-462b-9744-80bf6cdb388e # (4.9) Reconstruct the 1D image -# ... +recon_t2_star_se = plot(abs.(KomaMRI.fftc(raw_t2_star_se.profiles[1].data))) + +# ╔═╡ 34824db7-13c4-45e2-befa-f027b9b585c0 +[recon_t2_star_se recon_t2_star_gre recon_gre] # ╔═╡ fe8bbcd2-e8f5-4225-80c3-47e73176fb3d md""" @@ -1886,22 +1938,23 @@ version = "3.0.2+0" # ╠═9a88a54b-bcc7-41ad-8e60-f4d450dccb2d # ╠═0f96a83d-96ef-4768-9330-87c466e35c93 # ╟─97104c46-e81f-444a-957f-0bbb1b02f1b8 -# ╠═9f3683c1-4dfb-419b-9e04-f93bb7f80503 +# ╠═ee7e81e7-484c-44a8-a191-f73e24707ce9 # ╠═2ee7ba47-02e5-4b02-a162-ddbd5ed47c7b # ╟─27686262-1a1e-45fa-b4ee-90ae1d9ee34e # ╠═e4ef5145-a63c-4f91-ac04-3b5bf16c0842 # ╠═1a83d897-705b-443d-89a4-ea5e3e6a3c07 # ╠═18c82ff1-0bde-4fa0-848c-d0eb73d1ac7c # ╠═4a4a6bd3-b820-479c-89e3-f3ce79a316db +# ╠═f2d388d5-4cda-4a0b-be50-ea2cdc283692 # ╟─3357a283-a234-4d15-8fdf-7fbec58b33a7 -# ╠═c8a37593-3028-4e50-ad07-dc81edba45c8 -# ╠═75ee6dbe-598a-47be-9655-3de3bc015281 -# ╠═68d88987-3de7-42ae-9380-91ffae3ca40b +# ╠═27e65680-22a0-4079-b6df-d60a3218e52e # ╠═f1f3b700-5916-496f-b938-46f7f08b4eb6 +# ╠═4e1434e1-673f-4206-a271-9edec10ebd6a # ╟─45952512-aaf1-43d8-a95e-c32bb2633f42 # ╠═97479437-9ce3-4b33-9134-0f2af89bccb5 # ╠═1c79b37e-d4e0-490f-9466-20ce28f017ae # ╠═2e65ae31-f50a-462b-9744-80bf6cdb388e +# ╠═34824db7-13c4-45e2-befa-f027b9b585c0 # ╟─fe8bbcd2-e8f5-4225-80c3-47e73176fb3d # ╠═3b6b91cf-f3ad-40bc-9b3b-8bb5f395537f # ╟─00000000-0000-0000-0000-000000000001 diff --git a/examples/6.educational_pluto_notebook/simulation-example.html b/examples/6.educational_pluto_notebook/simulation-example.html index 82a6636cc..185802bee 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.html +++ b/examples/6.educational_pluto_notebook/simulation-example.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example.jl b/examples/6.educational_pluto_notebook/simulation-example.jl index 6ba83d327..8aca9ff5c 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.jl +++ b/examples/6.educational_pluto_notebook/simulation-example.jl @@ -4,16 +4,6 @@ using Markdown using InteractiveUtils -# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). -macro bind(def, element) - quote - local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end - local el = $(esc(element)) - global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) - el - end -end - # ╔═╡ 3e87790c-ddec-4897-a5d8-276cf7242147 begin using Pkg @@ -40,7 +30,7 @@ If you have any doubts on how to use a function, please search in the **Live Doc # ╔═╡ 8e474add-8651-431b-b481-7a139037dbd2 md"""# 1. Free Induction Decay (FID) -The free induction decay is the simplest observable NMR signal. This signal is the one that follows a single tipping RF pulse. +The free induction decay is the simplest observable NMR signal. This signal is the one that follows a single tipping RF pulse. $(PlutoUI.Resource("https://raw.githubusercontent.com/LIBREhub/MRI-processing-2023/main/02-simulation/Figures/FID.png", :width=>"300px")) To recreate this experiment, we will need to define a `Sequence`: @@ -48,29 +38,20 @@ To recreate this experiment, we will need to define a `Sequence`: - (1.2) An ADC to capture the signal in a variable `adc`, concatenate with (1.1) using `seq += adc` - (1.3) Plot the generated `Sequence` (check `plot_seq`'s docs) -For the hardware limits use the default scanner `sys = Scanner()`. +For the hardware limits use the default scanner `sys = Scanner()`. """ # ╔═╡ c6e33cb8-f42c-4643-9257-124d2804d3da # (1.1) A 90-deg block RF pulse -begin - sys = Scanner() - durRF = π/2/(2π*γ*sys.B1); #90-degree hard excitation pulse - rf = PulseDesigner.RF_hard(sys.B1, durRF, sys) -end +# ... # ╔═╡ 0266632d-5ca4-4196-a523-33a66dd70e0c # (1.2) An ADC to capture the signal -adc = ADC(100, 50e-3) +# ... # ╔═╡ 0975547d-67d9-4e6b-88ff-a9dd06a7f9ef # (1.3) Plot the generated Sequence -begin - seq = Sequence() - seq += rf - seq += adc - plot_seq(seq; slider=false) -end +# ... # ╔═╡ f11a2fa2-eff9-4979-b739-3da2b24a9a45 md""" @@ -85,17 +66,11 @@ Generate a virtual object: # ╔═╡ d16efa62-dce7-4ec3-9e3c-b5e1677377fc # (1.4) A Phantom with 20 spins -begin - obj = Phantom(x=collect(range(-1e-3,1e-3,20))) - obj.ρ .= 1 - obj.T1 .= 500e-3 - obj.T2 .= 50e-3 - obj -end +# ... # ╔═╡ 35ff3402-dc36-4b91-bec9-b4d21faf3e68 # (1.5) Plot the generated Phantom -plot_phantom_map(obj, :T1) +# ... # ╔═╡ ea542271-01c2-4962-a708-804b23a861b9 md""" @@ -106,21 +81,15 @@ md""" # ╔═╡ c47a50b8-c930-4c96-9b34-2772186634d9 # (1.6) Finally, use the generated seq, obj, and sys to simulate the FID -raw = simulate(obj, seq, sys) +# ... # ╔═╡ 7a66ab47-918f-4582-895f-1b4690562051 # (1.7) Plot the resulting raw data with plot_signal -plot_signal(raw; slider=false) +# ... # ╔═╡ 1231b832-47b1-4ccb-9b56-a67838598cc7 # (1.8) Is the signal the same as `plot(t, exp.(-t ./ T2))`? -begin - t = range(0, 50, 100) - plot( - scatter(x=t, y=20.0.*exp.(-t ./ 50)), - Layout(yaxis_range=[0, 20.1]) - ) -end +# ... # ╔═╡ e4c80c24-20fd-42e5-9dcd-a65958569c01 md""" @@ -128,67 +97,59 @@ md""" $(Resource("https://raw.githubusercontent.com/LIBREhub/MRI-processing-2023/main/02-simulation/Figures/GRE.gif", :width=>"400px")) -The gradient echo is one of the first steps to create an image. The big -breakthrough was the addition of linearly increasing magnetic fields, or gradients, to encode the spin's positions in their frequency (Mmmh, someone said Fourier?). This works due to the fact that the frequency $$f$$ of a spin is +The gradient echo is one of the first steps to create an image. The big +breakthrough was the addition of linearly increasing magnetic fields, or gradients, to encode the spin's positions in their frequency (Mmmh, someone said Fourier?). This works due to the fact that the frequency $$f$$ of a spin is $$f(x) = \frac{\gamma}{2\pi} B_z(x) = \frac{\gamma}{2\pi} G_x x.$$ Let's create a different sequence. - Create a 90-deg hard RF pulse and put it in a variable `seq_gre` - (2.1) Create a gradient with area `-Ax` using `gx_pre = Grad(A,T,rise,fall)` append to `seq_gre`. As an optional challenge, put `gx_pre.rise` and `gx_pre.fall` so the satisfy the `sys` requierements - - (2.2) Append a `Sequence` block called `readout` that includes: + - (2.2) Append a `Sequence` block called `readout` that includes: - A gradient of twice the area, or `2Ax`. Call it `gx` - An `ADC` with `adc2.delay = gx.rise` and `adc2.T = gx.T` - (2.3) Plot `seq_gre` and its k-space - (2.4) Plot the $$k$$-space with the `plot_kspace` function """ -# ╔═╡ 74666c1a-2673-4936-982b-6229bf92af66 -md""" - - (2.5) Simulate the `seq_gre` sequence - - (2.6) Plot the simulated signal - - (2.7) Reconstruct the 1D image - - (2.8) Do you notice anything weird? If the answer is yes, try adjusting `Ax` to change the `FOV` of the acquisition -""" - -# ╔═╡ 0f96a83d-96ef-4768-9330-87c466e35c93 -# (2.8) Do you notice anything weird? Change Ax! -@bind Ax Slider(range(0, 20, 20)*1e-5, default=10e-5) # Gradient's area in [T/m s] - # ╔═╡ 9179aa40-bb40-4a36-ae1e-00ae42935a5f # (2.1) Create a gradient `gx_pre`, use the variable `Ax`!! -begin - T_gx_pre = 10e-3 - gx_pre = Grad(-Ax/T_gx_pre, T_gx_pre, 0, 0) - seq_gre = Sequence() - seq_gre += rf - seq_gre += gx_pre +# ... + # (2.2) Append a `Sequence` block called `readout` - gx = Grad(2*Ax/(2T_gx_pre), 2T_gx_pre, 0, 0) - adc2 = ADC(100, 2T_gx_pre) - readout = Sequence([gx;;], [RF(0,0);;], [adc2]) - seq_gre += readout -end +# ... # ╔═╡ 8b4a1ad9-2d6a-4c8f-bb8e-f43c2d058195 # (2.3) Plot `seq_gre` and the k-space -plot_seq(seq_gre; slider=false) +# ... # ╔═╡ 3abca406-2e6b-4b37-8835-65cfad9d0caa # (2.4) Plot the $k$-space with the `plot_kspace` function -plot_kspace(seq_gre) +# ... + +# ╔═╡ 74666c1a-2673-4936-982b-6229bf92af66 +md""" + - (2.5) Simulate the `seq_gre` sequence + - (2.6) Plot the simulated signal + - (2.7) Reconstruct the 1D image + - (2.8) Do you notice anything weird? If the answer is yes, try adjusting `Ax` to change the `FOV` of the acquisition +""" # ╔═╡ ada602d2-4f4b-4fb4-a763-8a639e05ff38 # (2.5) Simulate the seq_gre sequence -raw_gre = simulate(obj, seq_gre, sys) +# ... # ╔═╡ 41d14dec-b852-4316-aefb-c3d08fa43216 # (2.6) Plot the simulated signal -signal_gre = plot_signal(raw_gre; slider=false) +# ... # ╔═╡ 9a88a54b-bcc7-41ad-8e60-f4d450dccb2d # (2.7) Reconstruct the 1D image -recon_gre = plot(abs.(KomaMRI.fftc(raw_gre.profiles[1].data))) +# ... + +# ╔═╡ 0f96a83d-96ef-4768-9330-87c466e35c93 +# (2.8) Do you notice anything weird? Change Ax! +# ... # ╔═╡ 97104c46-e81f-444a-957f-0bbb1b02f1b8 md""" @@ -215,56 +176,46 @@ In this excercise we will simplify this distribution, but we will obtain a simil """ -# ╔═╡ ee7e81e7-484c-44a8-a191-f73e24707ce9 -# (3.1) Create the obj_t2star phantom -begin - # (3.1.1) Empty phantom - obj_t2star = Phantom{Float64}(x=[]) - # (3.1.2) Iterate over linear off-resonance distribution - linear_offresonance_distribution = 2π .* range(-10, 10, 20) - for off = linear_offresonance_distribution - # (3.1.3) Copy original phantom and modify off-resonance - aux = copy(obj) - aux.Δw .= off - aux.y .+= off * 1e-6 # So the distribution is visible - # (3.1.4) Update the phantom - obj_t2star += aux - end - # (3.1.5) Divide the proton density - obj_t2star.ρ .= 1.0 / 20.0 - obj_t2star.name = "T2 star phantom" # Change the name of the phantom -end +# ╔═╡ 9f3683c1-4dfb-419b-9e04-f93bb7f80503 +# (3.1) Create a copy of the original phantom obj_t2star = copy(obj) + # (3.1.1) Empty phantom + # ... + # (3.1.2) Iterate over linear off-resonance distribution + # ... + # (3.1.3) Copy original phantom and modify off-resonance + # ... + # (3.1.4) Update the phantom + # ... + # (3.1.5) Divide the proton density + # ... # ╔═╡ 2ee7ba47-02e5-4b02-a162-ddbd5ed47c7b # (3.2) Plot obj_t2star -plot_phantom_map(obj_t2star, :Δw) +# ... # ╔═╡ 27686262-1a1e-45fa-b4ee-90ae1d9ee34e md""" - - (3.3) Simulate the `seq_gre` sequence - - (3.4) Plot the simulated signal - - (3.5) Compare the plot in (3.5) with (2.6) - - (3.6) Reconstruct the 1D image + - (3.4) Simulate the `seq_gre` sequence + - (3.5) Plot the simulated signal + - (3.6) Compare the plot in (3.5) with (2.6) + - (3.7) Reconstruct the 1D image """ # ╔═╡ e4ef5145-a63c-4f91-ac04-3b5bf16c0842 # (3.3) Simulate the seq_gre sequence -raw_t2_star_gre = simulate(obj_t2star, seq_gre, sys) +# ... # ╔═╡ 1a83d897-705b-443d-89a4-ea5e3e6a3c07 # (3.4) Plot the simulated signal -signal_t2_star_gre = plot_signal(raw_t2_star_gre; slider=false) +# ... # ╔═╡ 18c82ff1-0bde-4fa0-848c-d0eb73d1ac7c # (3.5) Compare the plot in (3.5) with (2.6) -[signal_gre; signal_t2_star_gre] +# ... # ╔═╡ 4a4a6bd3-b820-479c-89e3-f3ce79a316db # (3.6) Reconstruct the 1D image -recon_t2_star_gre = plot(abs.(KomaMRI.fftc(raw_t2_star_gre.profiles[1].data))) - -# ╔═╡ f2d388d5-4cda-4a0b-be50-ea2cdc283692 -[recon_gre recon_t2_star_gre] +# ... # ╔═╡ 3357a283-a234-4d15-8fdf-7fbec58b33a7 md""" @@ -285,24 +236,27 @@ Our sequence consists of: - (4.6) Plot `seq_se` and its k-space. Is the k-space the same as `seq_gre` in (2.3)? """ -# ╔═╡ 27e65680-22a0-4079-b6df-d60a3218e52e +# ╔═╡ c8a37593-3028-4e50-ad07-dc81edba45c8 # (4.1) A 90deg hard RF pulse -begin - seq_se = Sequence() - seq_se += rf +# ... + # (4.2) A `Delay` of TE/2 with a positive gradient (area `Ax`) - seq_se += -1*gx_pre - seq_se += (0.0+2.0im)*rf +# ... + # (4.3) A 180deg hard RF pulse - seq_se += readout -end +# ... + +# ╔═╡ 75ee6dbe-598a-47be-9655-3de3bc015281 +# (4.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in TE +# ... + +# ╔═╡ 68d88987-3de7-42ae-9380-91ffae3ca40b +# (4.5) Create concatenating these blocks into a sequence called `seq_se` +# ... # ╔═╡ f1f3b700-5916-496f-b938-46f7f08b4eb6 # (4.6) Plot seq_se and its k-space. Is the k-space the same as seq_gre in (2.3)? -plot_seq(seq_se; slider=false) - -# ╔═╡ 4e1434e1-673f-4206-a271-9edec10ebd6a -plot_kspace(seq_se) +# ... # ╔═╡ 45952512-aaf1-43d8-a95e-c32bb2633f42 md""" @@ -313,21 +267,15 @@ md""" # ╔═╡ 97479437-9ce3-4b33-9134-0f2af89bccb5 # (4.7) Simulate using seq_se and obj_t2star -raw_t2_star_se = simulate(obj_t2star, seq_se, sys) +# ... # ╔═╡ 1c79b37e-d4e0-490f-9466-20ce28f017ae # (4.8) Compare the signal obtained in (4.6) with the one at (3.5) -[ - plot_signal(raw_t2_star_se; slider=false); - plot_signal(raw_t2_star_gre; slider=false) -] +# ... # ╔═╡ 2e65ae31-f50a-462b-9744-80bf6cdb388e # (4.9) Reconstruct the 1D image -recon_t2_star_se = plot(abs.(KomaMRI.fftc(raw_t2_star_se.profiles[1].data))) - -# ╔═╡ 34824db7-13c4-45e2-befa-f027b9b585c0 -[recon_t2_star_se recon_t2_star_gre recon_gre] +# ... # ╔═╡ fe8bbcd2-e8f5-4225-80c3-47e73176fb3d md""" @@ -1938,23 +1886,22 @@ version = "3.0.2+0" # ╠═9a88a54b-bcc7-41ad-8e60-f4d450dccb2d # ╠═0f96a83d-96ef-4768-9330-87c466e35c93 # ╟─97104c46-e81f-444a-957f-0bbb1b02f1b8 -# ╠═ee7e81e7-484c-44a8-a191-f73e24707ce9 +# ╠═9f3683c1-4dfb-419b-9e04-f93bb7f80503 # ╠═2ee7ba47-02e5-4b02-a162-ddbd5ed47c7b # ╟─27686262-1a1e-45fa-b4ee-90ae1d9ee34e # ╠═e4ef5145-a63c-4f91-ac04-3b5bf16c0842 # ╠═1a83d897-705b-443d-89a4-ea5e3e6a3c07 # ╠═18c82ff1-0bde-4fa0-848c-d0eb73d1ac7c # ╠═4a4a6bd3-b820-479c-89e3-f3ce79a316db -# ╠═f2d388d5-4cda-4a0b-be50-ea2cdc283692 # ╟─3357a283-a234-4d15-8fdf-7fbec58b33a7 -# ╠═27e65680-22a0-4079-b6df-d60a3218e52e +# ╠═c8a37593-3028-4e50-ad07-dc81edba45c8 +# ╠═75ee6dbe-598a-47be-9655-3de3bc015281 +# ╠═68d88987-3de7-42ae-9380-91ffae3ca40b # ╠═f1f3b700-5916-496f-b938-46f7f08b4eb6 -# ╠═4e1434e1-673f-4206-a271-9edec10ebd6a # ╟─45952512-aaf1-43d8-a95e-c32bb2633f42 # ╠═97479437-9ce3-4b33-9134-0f2af89bccb5 # ╠═1c79b37e-d4e0-490f-9466-20ce28f017ae # ╠═2e65ae31-f50a-462b-9744-80bf6cdb388e -# ╠═34824db7-13c4-45e2-befa-f027b9b585c0 # ╟─fe8bbcd2-e8f5-4225-80c3-47e73176fb3d # ╠═3b6b91cf-f3ad-40bc-9b3b-8bb5f395537f # ╟─00000000-0000-0000-0000-000000000001 From adaa322a7898b1cefc2f2e48124daba339136a7f Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Tue, 19 Dec 2023 11:39:42 -0300 Subject: [PATCH 06/15] Add a slider in the Pluto file with no solution --- .../simulation-example.html | 4 ++-- .../simulation-example.jl | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/examples/6.educational_pluto_notebook/simulation-example.html b/examples/6.educational_pluto_notebook/simulation-example.html index 185802bee..f555e027f 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.html +++ b/examples/6.educational_pluto_notebook/simulation-example.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example.jl b/examples/6.educational_pluto_notebook/simulation-example.jl index 8aca9ff5c..b651434ee 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.jl +++ b/examples/6.educational_pluto_notebook/simulation-example.jl @@ -4,6 +4,16 @@ using Markdown using InteractiveUtils +# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). +macro bind(def, element) + quote + local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end + local el = $(esc(element)) + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) + el + end +end + # ╔═╡ 3e87790c-ddec-4897-a5d8-276cf7242147 begin using Pkg @@ -112,6 +122,13 @@ Let's create a different sequence. - (2.4) Plot the $$k$$-space with the `plot_kspace` function """ +# ╔═╡ 2b237108-bfbc-4e52-b991-2e413194c4ef +# Define `Ax` (value defined by a slider) +@bind Ax Slider(range(0, 20, 20)*1e-5, default=10e-5) # Gradient's area in [T/m s] + +# ╔═╡ 48bb2560-370b-461e-8b1e-adc40c9e74a7 +Ax + # ╔═╡ 9179aa40-bb40-4a36-ae1e-00ae42935a5f # (2.1) Create a gradient `gx_pre`, use the variable `Ax`!! # ... @@ -1877,6 +1894,8 @@ version = "3.0.2+0" # ╠═7a66ab47-918f-4582-895f-1b4690562051 # ╠═1231b832-47b1-4ccb-9b56-a67838598cc7 # ╟─e4c80c24-20fd-42e5-9dcd-a65958569c01 +# ╠═2b237108-bfbc-4e52-b991-2e413194c4ef +# ╠═48bb2560-370b-461e-8b1e-adc40c9e74a7 # ╠═9179aa40-bb40-4a36-ae1e-00ae42935a5f # ╠═8b4a1ad9-2d6a-4c8f-bb8e-f43c2d058195 # ╠═3abca406-2e6b-4b37-8835-65cfad9d0caa From 65bc66048a37bb4570932ce0bc509c1316aaa1a2 Mon Sep 17 00:00:00 2001 From: Carlos Castillo Passi Date: Tue, 19 Dec 2023 12:48:03 -0300 Subject: [PATCH 07/15] Update examples/6.educational_pluto_notebook/simulation-example-solution.jl --- .../simulation-example-solution.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.jl b/examples/6.educational_pluto_notebook/simulation-example-solution.jl index 6ba83d327..80c4f8ff6 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.jl +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.jl @@ -204,12 +204,12 @@ $$p_{\Delta w}(w) = \frac{T_2^{'}}{\pi(1+T_2^{'2} w^2)},\quad\text{with }\frac{1 In this excercise we will simplify this distribution, but we will obtain a similar effect. -- (3.1) Create a new phantom named `obj_t2star` with spins at the same positions as the original phantom `obj`, each having a linear distribution of the off-resonance parameter. To achieve this, follow these steps: +- (3.1) Create a new phantom named `obj_t2star` with spins at the same positions as the original phantom `obj`, each having a linear distribution of off-resonance. To achieve this, follow these steps: * (3.1.1) Create an empty phantom called `obj_t2star`. - * (3.1.2) Iterate over 20 equispaced values starting from -20π up to 20π; these values represent the linear off-resonance distribution. - * (3.1.3) Within the loop, create a copy of the original phantom: `obj_aux = copy(obj)` with the off-resonance value of the current iteration. - * (3.1.4) Within the loop, update the `obj_t2star` by superimposing it with `obj_aux`. - * (3.1.5) Finally, outside the loop, divide the proton density of `obj_t2star` by 20. + * (3.1.2) Create a linear off-resonance distribution such that the range $2\pi [-10, 10]\,\mathrm{rad/s}` is covered uniformly with $N_{\mathrm{isochromats}} = 20$ (use the function `range(start, stop, length)`). + * (3.1.3) Iterate over the elements `off` of the linear distribution (`for` loop) and create copies of the original phantom (`obj_aux = copy(obj)`) and set the off-resonance of that copy to `off` with `obj_aux.Δw .= off`. + * (3.1.4) Update `obj_t2star` by appending the modified copies `obj_aux` (`obj_t2star += obj_aux`). + * (3.1.5) Finally, outside the loop, divide the proton density `obj_t2star.ρ` by $N_{\mathrm{isochromats}} = 20$ and rename the phantom `obj_t2star.name = "T2 star phantom"`. - (3.2) Plot `obj_t2star` with `plot_phantom_map(obj_t2star, :Δw)` and verify it is correct From 81db429fd3a54aa304d1dd5169f92d879fab01dd Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Tue, 19 Dec 2023 13:27:46 -0300 Subject: [PATCH 08/15] Update Pluto example --- .../simulation-example-solution.html | 4 ++-- .../simulation-example-solution.jl | 17 ++++++++------- .../simulation-example.html | 4 ++-- .../simulation-example.jl | 21 ++++++++++--------- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.html b/examples/6.educational_pluto_notebook/simulation-example-solution.html index 82a6636cc..82f6405cf 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.html +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.jl b/examples/6.educational_pluto_notebook/simulation-example-solution.jl index 80c4f8ff6..7f3d5f08b 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.jl +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.jl @@ -206,33 +206,34 @@ In this excercise we will simplify this distribution, but we will obtain a simil - (3.1) Create a new phantom named `obj_t2star` with spins at the same positions as the original phantom `obj`, each having a linear distribution of off-resonance. To achieve this, follow these steps: * (3.1.1) Create an empty phantom called `obj_t2star`. - * (3.1.2) Create a linear off-resonance distribution such that the range $2\pi [-10, 10]\,\mathrm{rad/s}` is covered uniformly with $N_{\mathrm{isochromats}} = 20$ (use the function `range(start, stop, length)`). + * (3.1.2) Create a linear off-resonance distribution such that the range $$2\pi [-10, 10]\,\mathrm{rad/s}$$ is covered uniformly with $$N_{\mathrm{isochromats}} = 20$$ (use the function `range(start, stop, length)`). * (3.1.3) Iterate over the elements `off` of the linear distribution (`for` loop) and create copies of the original phantom (`obj_aux = copy(obj)`) and set the off-resonance of that copy to `off` with `obj_aux.Δw .= off`. * (3.1.4) Update `obj_t2star` by appending the modified copies `obj_aux` (`obj_t2star += obj_aux`). - * (3.1.5) Finally, outside the loop, divide the proton density `obj_t2star.ρ` by $N_{\mathrm{isochromats}} = 20$ and rename the phantom `obj_t2star.name = "T2 star phantom"`. + * (3.1.5) Finally, outside the loop, divide the proton density `obj_t2star.ρ` by $$N_{\mathrm{isochromats}} = 20$$ and rename the phantom `obj_t2star.name = "T2 star phantom"`. - (3.2) Plot `obj_t2star` with `plot_phantom_map(obj_t2star, :Δw)` and verify it is correct """ # ╔═╡ ee7e81e7-484c-44a8-a191-f73e24707ce9 -# (3.1) Create the obj_t2star phantom +# (3.1) Create the new obj_t2star phantom begin - # (3.1.1) Empty phantom + # (3.1.1) Create an empty phantom obj_t2star = Phantom{Float64}(x=[]) - # (3.1.2) Iterate over linear off-resonance distribution + # (3.1.2) Define the linear off-resonance distribution linear_offresonance_distribution = 2π .* range(-10, 10, 20) + # (3.1.3) Iterate over the linear off-resonance distribution and ... for off = linear_offresonance_distribution - # (3.1.3) Copy original phantom and modify off-resonance + # ... copy the original phantom and modify its off-resonance aux = copy(obj) aux.Δw .= off aux.y .+= off * 1e-6 # So the distribution is visible # (3.1.4) Update the phantom obj_t2star += aux end - # (3.1.5) Divide the proton density + # (3.1.5) Divide the proton density and rename the phantom obj_t2star.ρ .= 1.0 / 20.0 - obj_t2star.name = "T2 star phantom" # Change the name of the phantom + obj_t2star.name = "T2 star phantom" end # ╔═╡ 2ee7ba47-02e5-4b02-a162-ddbd5ed47c7b diff --git a/examples/6.educational_pluto_notebook/simulation-example.html b/examples/6.educational_pluto_notebook/simulation-example.html index f555e027f..5faf0a43a 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.html +++ b/examples/6.educational_pluto_notebook/simulation-example.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example.jl b/examples/6.educational_pluto_notebook/simulation-example.jl index b651434ee..a7bcecbd1 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.jl +++ b/examples/6.educational_pluto_notebook/simulation-example.jl @@ -182,28 +182,29 @@ $$p_{\Delta w}(w) = \frac{T_2^{'}}{\pi(1+T_2^{'2} w^2)},\quad\text{with }\frac{1 In this excercise we will simplify this distribution, but we will obtain a similar effect. -- (3.1) Create a new phantom named `obj_t2star` with spins at the same positions as the original phantom `obj`, each having a linear distribution of the off-resonance parameter. To achieve this, follow these steps: +- (3.1) Create a new phantom named `obj_t2star` with spins at the same positions as the original phantom `obj`, each having a linear distribution of off-resonance. To achieve this, follow these steps: * (3.1.1) Create an empty phantom called `obj_t2star`. - * (3.1.2) Iterate over 20 equispaced values starting from -20π up to 20π; these values represent the linear off-resonance distribution. - * (3.1.3) Within the loop, create a copy of the original phantom: `obj_aux = copy(obj)` with the off-resonance value of the current iteration. - * (3.1.4) Within the loop, update the `obj_t2star` by superimposing it with `obj_aux`. - * (3.1.5) Finally, outside the loop, divide the proton density of `obj_t2star` by 20. + * (3.1.2) Create a linear off-resonance distribution such that the range $$2\pi [-10, 10]\,\mathrm{rad/s}$$ is covered uniformly with $$N_{\mathrm{isochromats}} = 20$$ (use the function `range(start, stop, length)`). + * (3.1.3) Iterate over the elements `off` of the linear distribution (`for` loop) and create copies of the original phantom (`obj_aux = copy(obj)`) and set the off-resonance of that copy to `off` with `obj_aux.Δw .= off`. + * (3.1.4) Update `obj_t2star` by appending the modified copies `obj_aux` (`obj_t2star += obj_aux`). + * (3.1.5) Finally, outside the loop, divide the proton density `obj_t2star.ρ` by $$N_{\mathrm{isochromats}} = 20$$ and rename the phantom `obj_t2star.name = "T2 star phantom"`. - (3.2) Plot `obj_t2star` with `plot_phantom_map(obj_t2star, :Δw)` and verify it is correct """ # ╔═╡ 9f3683c1-4dfb-419b-9e04-f93bb7f80503 -# (3.1) Create a copy of the original phantom obj_t2star = copy(obj) - # (3.1.1) Empty phantom +# (3.1) Create the new phantom obj_t2star + # (3.1.1) Create an empty phantom # ... - # (3.1.2) Iterate over linear off-resonance distribution + # (3.1.2) Define the linear off-resonance distribution # ... - # (3.1.3) Copy original phantom and modify off-resonance + # (3.1.3) Iterate over the linear off-resonance distribution and + # copy the original phantom and modify its off-resonance # ... # (3.1.4) Update the phantom # ... - # (3.1.5) Divide the proton density + # (3.1.5) Divide the proton density and rename the phantom # ... # ╔═╡ 2ee7ba47-02e5-4b02-a162-ddbd5ed47c7b From 91702ae560fffca91ab04cbee4c779daad88608a Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Wed, 20 Dec 2023 10:44:27 -0300 Subject: [PATCH 09/15] Update plots in Pluto example --- .../simulation-example-solution.html | 4 +- .../simulation-example-solution.jl | 109 +++++++++++------- .../simulation-example.html | 4 +- .../simulation-example.jl | 82 +++++-------- 4 files changed, 99 insertions(+), 100 deletions(-) diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.html b/examples/6.educational_pluto_notebook/simulation-example-solution.html index 82f6405cf..c1d008622 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.html +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.jl b/examples/6.educational_pluto_notebook/simulation-example-solution.jl index 7f3d5f08b..cac12b7c9 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.jl +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.jl @@ -25,7 +25,7 @@ using KomaMRI, PlutoPlotly, PlutoUI # ╔═╡ cc66bfed-b61b-4067-8c94-4c54b82a3b42 md""" -These are the versions of KomaMRI and their subpackages. +These are the versions of KomaMRI and its subpackages. """ # ╔═╡ 8529f36d-2d39-4b45-a821-01c8346539fd @@ -33,14 +33,14 @@ TableOfContents() # There should be a table of contents on the right ---> # ╔═╡ 6dfe338d-de85-4adb-b030-09455fae78a0 md""" -Welcome to the hand-on session on MRI simulation. Let's have some fun! +Welcome to the hands-on session on MRI simulation. Let's have some fun! -If you have any doubts on how to use a function, please search in the **Live Docs** at the bottom right. +If you have any doubts about how to use a function, please search in the **Live Docs** at the bottom right. """ # ╔═╡ 8e474add-8651-431b-b481-7a139037dbd2 md"""# 1. Free Induction Decay (FID) -The free induction decay is the simplest observable NMR signal. This signal is the one that follows a single tipping RF pulse. +The free induction decay is the simplest observable NMR signal. This signal is the one that follows a single tipping RF pulse. $(PlutoUI.Resource("https://raw.githubusercontent.com/LIBREhub/MRI-processing-2023/main/02-simulation/Figures/FID.png", :width=>"300px")) To recreate this experiment, we will need to define a `Sequence`: @@ -90,7 +90,7 @@ begin obj.ρ .= 1 obj.T1 .= 500e-3 obj.T2 .= 50e-3 - obj + nothing end # ╔═╡ 35ff3402-dc36-4b91-bec9-b4d21faf3e68 @@ -184,7 +184,13 @@ raw_gre = simulate(obj, seq_gre, sys) # ╔═╡ 41d14dec-b852-4316-aefb-c3d08fa43216 # (2.6) Plot the simulated signal -signal_gre = plot_signal(raw_gre; slider=false) +begin + t_decay = range(10.587, 30.587, 100) + trace_decay = scatter(x=t_decay, y=20.0.*exp.(-t_decay ./ 50), name="T2-decay", marker_color="purple") + signal_gre = plot_signal(raw_gre; slider=false) + addtraces!(signal_gre, trace_decay) + signal_gre +end # ╔═╡ 9a88a54b-bcc7-41ad-8e60-f4d450dccb2d # (2.7) Reconstruct the 1D image @@ -194,7 +200,7 @@ recon_gre = plot(abs.(KomaMRI.fftc(raw_gre.profiles[1].data))) md""" # 3. $T_{2}^{*}$-decay -The $$T_{2}^{*}$$-decay it the signal decay produced by microscopic distribution of off-resonance. +The $$T_{2}^{*}$$-decay is the signal decay produced by microscopic distribution of off-resonance. $(Resource("https://raw.githubusercontent.com/LIBREhub/MRI-processing-2023/main/02-simulation/Figures/T2star.png", :width=>"400px")) @@ -254,18 +260,34 @@ raw_t2_star_gre = simulate(obj_t2star, seq_gre, sys) # ╔═╡ 1a83d897-705b-443d-89a4-ea5e3e6a3c07 # (3.4) Plot the simulated signal -signal_t2_star_gre = plot_signal(raw_t2_star_gre; slider=false) +begin + signal_t2_star_gre = plot_signal(raw_t2_star_gre; slider=false) + addtraces!(signal_t2_star_gre, trace_decay) + signal_t2_star_gre +end # ╔═╡ 18c82ff1-0bde-4fa0-848c-d0eb73d1ac7c # (3.5) Compare the plot in (3.5) with (2.6) -[signal_gre; signal_t2_star_gre] +begin + signal_layout = Layout(yaxis=attr(range=[-5, 16.5])) + relayout!(signal_gre, signal_layout; title="GRE-T2") + relayout!(signal_t2_star_gre, signal_layout; title="GRE-T2*") + fig_signal_2 = [signal_gre signal_t2_star_gre] + relayout(fig_signal_2, showlegend=false) +end # ╔═╡ 4a4a6bd3-b820-479c-89e3-f3ce79a316db # (3.6) Reconstruct the 1D image recon_t2_star_gre = plot(abs.(KomaMRI.fftc(raw_t2_star_gre.profiles[1].data))) -# ╔═╡ f2d388d5-4cda-4a0b-be50-ea2cdc283692 -[recon_gre recon_t2_star_gre] +# ╔═╡ 964404f6-7f46-4df9-ad98-921948c3be69 +begin + recon_layout = Layout(yaxis=attr(range=[0, 0.8])) + relayout!(recon_gre, recon_layout; title="GRE-T2") + relayout!(recon_t2_star_gre, recon_layout; title="GRE-T2*") + fig_recon_2 = [recon_gre recon_t2_star_gre] + relayout(fig_recon_2, showlegend=false) +end # ╔═╡ 3357a283-a234-4d15-8fdf-7fbec58b33a7 md""" @@ -277,29 +299,31 @@ The spin echo experiment has the advantage that the echo signal amplitud it is m For this section we will use the phantom `obj_t2star` and a new sequence `seq_se`. -Our sequence consists of: - - (4.1) A 90deg hard RF pulse - - (4.2) A `Delay` of $$\mathrm{TE}/2$$ with a positive gradient (area `Ax`) - - (4.3) A 180deg hard RF pulse - - (4.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in $$\mathrm{TE}$$ - - (4.5) Create concatenating these blocks into a sequence called `seq_se` - - (4.6) Plot `seq_se` and its k-space. Is the k-space the same as `seq_gre` in (2.3)? +- (4.1) Create a sequence called `seq_se` with the following blocks: + * (4.1.1) A 90deg hard RF pulse + * (4.1.2) A `Delay` of $$\mathrm{TE}/2$$ with a positive gradient (area `Ax`) + * (4.1.3) A 180deg hard RF pulse + * (4.1.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in $$\mathrm{TE}$$ + + - (4.2) Plot `seq_se` and its k-space. Is the k-space the same as `seq_gre` in (2.3)? """ # ╔═╡ 27e65680-22a0-4079-b6df-d60a3218e52e -# (4.1) A 90deg hard RF pulse +# (4.1) Create a Spin Echo sequence `seq_se` begin + # (4.1.1) A 90deg hard RF pulse seq_se = Sequence() seq_se += rf -# (4.2) A `Delay` of TE/2 with a positive gradient (area `Ax`) + # (4.1.2) A `Delay` of TE/2 with a positive gradient (area `Ax`) seq_se += -1*gx_pre + # (4.1.3) A 180deg hard RF pulse seq_se += (0.0+2.0im)*rf -# (4.3) A 180deg hard RF pulse + # (4.1.4) A readout gradient seq_se += readout end # ╔═╡ f1f3b700-5916-496f-b938-46f7f08b4eb6 -# (4.6) Plot seq_se and its k-space. Is the k-space the same as seq_gre in (2.3)? +# (4.2) Plot seq_se and its k-space. Is the k-space the same as seq_gre in (2.3)? plot_seq(seq_se; slider=false) # ╔═╡ 4e1434e1-673f-4206-a271-9edec10ebd6a @@ -307,43 +331,41 @@ plot_kspace(seq_se) # ╔═╡ 45952512-aaf1-43d8-a95e-c32bb2633f42 md""" - - (4.7) Simulate using `seq_se` and `obj_t2star` - - (4.8) Compare the signal obtained in (4.6) with the one at (3.5) - - (4.9) Reconstruct the 1D image + - (4.3) Simulate using `seq_se` and `obj_t2star` + - (4.4) Compare the signal obtained in (4.6) with the one at (3.5) + - (4.5) Reconstruct the 1D image """ # ╔═╡ 97479437-9ce3-4b33-9134-0f2af89bccb5 -# (4.7) Simulate using seq_se and obj_t2star +# (4.3) Simulate using seq_se and obj_t2star raw_t2_star_se = simulate(obj_t2star, seq_se, sys) # ╔═╡ 1c79b37e-d4e0-490f-9466-20ce28f017ae -# (4.8) Compare the signal obtained in (4.6) with the one at (3.5) -[ - plot_signal(raw_t2_star_se; slider=false); - plot_signal(raw_t2_star_gre; slider=false) -] +# (4.4) Compare the signal obtained in (4.6) with the one at (3.5) +begin + signal_t2_star_se = plot_signal(raw_t2_star_se; slider=false) + addtraces!(signal_t2_star_se, trace_decay) + relayout!(signal_t2_star_se, signal_layout; title="SE") + fig_signal_3 = [signal_gre signal_t2_star_gre signal_t2_star_se] + relayout(fig_signal_3, showlegend=false) +end # ╔═╡ 2e65ae31-f50a-462b-9744-80bf6cdb388e -# (4.9) Reconstruct the 1D image +# (4.5) Reconstruct the 1D image recon_t2_star_se = plot(abs.(KomaMRI.fftc(raw_t2_star_se.profiles[1].data))) # ╔═╡ 34824db7-13c4-45e2-befa-f027b9b585c0 -[recon_t2_star_se recon_t2_star_gre recon_gre] +begin + relayout!(recon_t2_star_se, recon_layout; title="SE") + fig_recon_3 = [recon_gre recon_t2_star_gre recon_t2_star_se] + relayout(fig_recon_3, showlegend=false) +end # ╔═╡ fe8bbcd2-e8f5-4225-80c3-47e73176fb3d md""" Congratulations! you finished the simulation hands-on session 🥳! """ -# ╔═╡ 3b6b91cf-f3ad-40bc-9b3b-8bb5f395537f -# Run this cell to celebrate! -html""" - -""" - # ╔═╡ 00000000-0000-0000-0000-000000000001 PLUTO_PROJECT_TOML_CONTENTS = """ [deps] @@ -1946,7 +1968,7 @@ version = "3.0.2+0" # ╠═1a83d897-705b-443d-89a4-ea5e3e6a3c07 # ╠═18c82ff1-0bde-4fa0-848c-d0eb73d1ac7c # ╠═4a4a6bd3-b820-479c-89e3-f3ce79a316db -# ╠═f2d388d5-4cda-4a0b-be50-ea2cdc283692 +# ╠═964404f6-7f46-4df9-ad98-921948c3be69 # ╟─3357a283-a234-4d15-8fdf-7fbec58b33a7 # ╠═27e65680-22a0-4079-b6df-d60a3218e52e # ╠═f1f3b700-5916-496f-b938-46f7f08b4eb6 @@ -1957,6 +1979,5 @@ version = "3.0.2+0" # ╠═2e65ae31-f50a-462b-9744-80bf6cdb388e # ╠═34824db7-13c4-45e2-befa-f027b9b585c0 # ╟─fe8bbcd2-e8f5-4225-80c3-47e73176fb3d -# ╠═3b6b91cf-f3ad-40bc-9b3b-8bb5f395537f # ╟─00000000-0000-0000-0000-000000000001 # ╟─00000000-0000-0000-0000-000000000002 diff --git a/examples/6.educational_pluto_notebook/simulation-example.html b/examples/6.educational_pluto_notebook/simulation-example.html index 5faf0a43a..6d7b970cf 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.html +++ b/examples/6.educational_pluto_notebook/simulation-example.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example.jl b/examples/6.educational_pluto_notebook/simulation-example.jl index a7bcecbd1..9b017a36a 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.jl +++ b/examples/6.educational_pluto_notebook/simulation-example.jl @@ -25,7 +25,7 @@ using KomaMRI, PlutoPlotly, PlutoUI # ╔═╡ cc66bfed-b61b-4067-8c94-4c54b82a3b42 md""" -These are the versions of KomaMRI and their subpackages. +These are the versions of KomaMRI and its subpackages. """ # ╔═╡ 8529f36d-2d39-4b45-a821-01c8346539fd @@ -33,9 +33,9 @@ TableOfContents() # There should be a table of contents on the right ---> # ╔═╡ 6dfe338d-de85-4adb-b030-09455fae78a0 md""" -Welcome to the hand-on session on MRI simulation. Let's have some fun! +Welcome to the hands-on session on MRI simulation. Let's have some fun! -If you have any doubts on how to use a function, please search in the **Live Docs** at the bottom right. +If you have any doubts about how to use a function, please search in the **Live Docs** at the bottom right. """ # ╔═╡ 8e474add-8651-431b-b481-7a139037dbd2 @@ -122,13 +122,6 @@ Let's create a different sequence. - (2.4) Plot the $$k$$-space with the `plot_kspace` function """ -# ╔═╡ 2b237108-bfbc-4e52-b991-2e413194c4ef -# Define `Ax` (value defined by a slider) -@bind Ax Slider(range(0, 20, 20)*1e-5, default=10e-5) # Gradient's area in [T/m s] - -# ╔═╡ 48bb2560-370b-461e-8b1e-adc40c9e74a7 -Ax - # ╔═╡ 9179aa40-bb40-4a36-ae1e-00ae42935a5f # (2.1) Create a gradient `gx_pre`, use the variable `Ax`!! # ... @@ -166,13 +159,18 @@ md""" # ╔═╡ 0f96a83d-96ef-4768-9330-87c466e35c93 # (2.8) Do you notice anything weird? Change Ax! -# ... + +# ╔═╡ 2b237108-bfbc-4e52-b991-2e413194c4ef +# Define `Ax` (value defined by a slider) +md""" +Ax $(@bind Ax Slider(range(0, 20, 20)*1e-5, default=10e-5, show_value=true)) [T/m s] +""" # ╔═╡ 97104c46-e81f-444a-957f-0bbb1b02f1b8 md""" # 3. $T_{2}^{*}$-decay -The $$T_{2}^{*}$$-decay it the signal decay produced by microscopic distribution of off-resonance. +The $$T_{2}^{*}$$-decay is the signal decay produced by microscopic distribution of off-resonance. $(Resource("https://raw.githubusercontent.com/LIBREhub/MRI-processing-2023/main/02-simulation/Figures/T2star.png", :width=>"400px")) @@ -245,54 +243,47 @@ The spin echo experiment has the advantage that the echo signal amplitud it is m For this section we will use the phantom `obj_t2star` and a new sequence `seq_se`. -Our sequence consists of: - - (4.1) A 90deg hard RF pulse - - (4.2) A `Delay` of $$\mathrm{TE}/2$$ with a positive gradient (area `Ax`) - - (4.3) A 180deg hard RF pulse - - (4.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in $$\mathrm{TE}$$ - - (4.5) Create concatenating these blocks into a sequence called `seq_se` - - (4.6) Plot `seq_se` and its k-space. Is the k-space the same as `seq_gre` in (2.3)? +- (4.1) Create a sequence called `seq_se` concatenating the following blocks: + * (4.1.1) A 90deg hard RF pulse + * (4.1.2) A `Delay` of $$\mathrm{TE}/2$$ with a positive gradient (area `Ax`) + * (4.1.3) A 180deg hard RF pulse + * (4.1.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in $$\mathrm{TE}$$ + + - (4.2) Plot `seq_se` and its k-space. Is the k-space the same as `seq_gre` in (2.3)? """ # ╔═╡ c8a37593-3028-4e50-ad07-dc81edba45c8 -# (4.1) A 90deg hard RF pulse -# ... - -# (4.2) A `Delay` of TE/2 with a positive gradient (area `Ax`) +# (4.1) Create a Spin Echo sequence `seq_se` +# (4.1.1) A 90deg hard RF pulse # ... - -# (4.3) A 180deg hard RF pulse +# (4.1.2) A `Delay` of TE/2 with a positive gradient (area `Ax`) # ... - -# ╔═╡ 75ee6dbe-598a-47be-9655-3de3bc015281 -# (4.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in TE +# (4.1.3) A 180deg hard RF pulse # ... - -# ╔═╡ 68d88987-3de7-42ae-9380-91ffae3ca40b -# (4.5) Create concatenating these blocks into a sequence called `seq_se` +# (4.1.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in TE # ... # ╔═╡ f1f3b700-5916-496f-b938-46f7f08b4eb6 -# (4.6) Plot seq_se and its k-space. Is the k-space the same as seq_gre in (2.3)? +# (4.2) Plot seq_se and its k-space. Is the k-space the same as seq_gre in (2.3)? # ... # ╔═╡ 45952512-aaf1-43d8-a95e-c32bb2633f42 md""" - - (4.7) Simulate using `seq_se` and `obj_t2star` - - (4.8) Compare the signal obtained in (4.6) with the one at (3.5) - - (4.9) Reconstruct the 1D image + - (4.3) Simulate using `seq_se` and `obj_t2star` + - (4.4) Compare the signal obtained in (4.6) with the one at (3.5) + - (4.5) Reconstruct the 1D image """ # ╔═╡ 97479437-9ce3-4b33-9134-0f2af89bccb5 -# (4.7) Simulate using seq_se and obj_t2star +# (4.3) Simulate using seq_se and obj_t2star # ... # ╔═╡ 1c79b37e-d4e0-490f-9466-20ce28f017ae -# (4.8) Compare the signal obtained in (4.6) with the one at (3.5) +# (4.4) Compare the signal obtained in (4.6) with the one at (3.5) # ... # ╔═╡ 2e65ae31-f50a-462b-9744-80bf6cdb388e -# (4.9) Reconstruct the 1D image +# (4.5) Reconstruct the 1D image # ... # ╔═╡ fe8bbcd2-e8f5-4225-80c3-47e73176fb3d @@ -300,15 +291,6 @@ md""" Congratulations! you finished the simulation hands-on session 🥳! """ -# ╔═╡ 3b6b91cf-f3ad-40bc-9b3b-8bb5f395537f -# Run this cell to celebrate! -html""" - -""" - # ╔═╡ 00000000-0000-0000-0000-000000000001 PLUTO_PROJECT_TOML_CONTENTS = """ [deps] @@ -1895,8 +1877,6 @@ version = "3.0.2+0" # ╠═7a66ab47-918f-4582-895f-1b4690562051 # ╠═1231b832-47b1-4ccb-9b56-a67838598cc7 # ╟─e4c80c24-20fd-42e5-9dcd-a65958569c01 -# ╠═2b237108-bfbc-4e52-b991-2e413194c4ef -# ╠═48bb2560-370b-461e-8b1e-adc40c9e74a7 # ╠═9179aa40-bb40-4a36-ae1e-00ae42935a5f # ╠═8b4a1ad9-2d6a-4c8f-bb8e-f43c2d058195 # ╠═3abca406-2e6b-4b37-8835-65cfad9d0caa @@ -1905,6 +1885,7 @@ version = "3.0.2+0" # ╠═41d14dec-b852-4316-aefb-c3d08fa43216 # ╠═9a88a54b-bcc7-41ad-8e60-f4d450dccb2d # ╠═0f96a83d-96ef-4768-9330-87c466e35c93 +# ╟─2b237108-bfbc-4e52-b991-2e413194c4ef # ╟─97104c46-e81f-444a-957f-0bbb1b02f1b8 # ╠═9f3683c1-4dfb-419b-9e04-f93bb7f80503 # ╠═2ee7ba47-02e5-4b02-a162-ddbd5ed47c7b @@ -1915,14 +1896,11 @@ version = "3.0.2+0" # ╠═4a4a6bd3-b820-479c-89e3-f3ce79a316db # ╟─3357a283-a234-4d15-8fdf-7fbec58b33a7 # ╠═c8a37593-3028-4e50-ad07-dc81edba45c8 -# ╠═75ee6dbe-598a-47be-9655-3de3bc015281 -# ╠═68d88987-3de7-42ae-9380-91ffae3ca40b # ╠═f1f3b700-5916-496f-b938-46f7f08b4eb6 # ╟─45952512-aaf1-43d8-a95e-c32bb2633f42 # ╠═97479437-9ce3-4b33-9134-0f2af89bccb5 # ╠═1c79b37e-d4e0-490f-9466-20ce28f017ae # ╠═2e65ae31-f50a-462b-9744-80bf6cdb388e # ╟─fe8bbcd2-e8f5-4225-80c3-47e73176fb3d -# ╠═3b6b91cf-f3ad-40bc-9b3b-8bb5f395537f # ╟─00000000-0000-0000-0000-000000000001 # ╟─00000000-0000-0000-0000-000000000002 From 2cfddce47bc7ef63e1ae2a6296e51305f20fef6d Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Wed, 20 Dec 2023 11:47:08 -0300 Subject: [PATCH 10/15] Define one trace for T2-decay in Pluto example --- .../simulation-example-solution.html | 4 ++-- .../simulation-example-solution.jl | 15 ++++++--------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.html b/examples/6.educational_pluto_notebook/simulation-example-solution.html index c1d008622..a381c1a72 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.html +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.jl b/examples/6.educational_pluto_notebook/simulation-example-solution.jl index cac12b7c9..928f757ba 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.jl +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.jl @@ -116,10 +116,8 @@ plot_signal(raw; slider=false) # (1.8) Is the signal the same as `plot(t, exp.(-t ./ T2))`? begin t = range(0, 50, 100) - plot( - scatter(x=t, y=20.0.*exp.(-t ./ 50)), - Layout(yaxis_range=[0, 20.1]) - ) + t2_decay(t) = scatter(x=t, y=20.0.*exp.(-t ./ 50), name="T2-decay", marker_color="purple") + plot(t2_decay(t), Layout(yaxis_range=[0, 20.1])) end # ╔═╡ e4c80c24-20fd-42e5-9dcd-a65958569c01 @@ -185,10 +183,9 @@ raw_gre = simulate(obj, seq_gre, sys) # ╔═╡ 41d14dec-b852-4316-aefb-c3d08fa43216 # (2.6) Plot the simulated signal begin - t_decay = range(10.587, 30.587, 100) - trace_decay = scatter(x=t_decay, y=20.0.*exp.(-t_decay ./ 50), name="T2-decay", marker_color="purple") + t_adc = range(10.587, 30.587, 100) signal_gre = plot_signal(raw_gre; slider=false) - addtraces!(signal_gre, trace_decay) + addtraces!(signal_gre, t2_decay(t_adc)) signal_gre end @@ -262,7 +259,7 @@ raw_t2_star_gre = simulate(obj_t2star, seq_gre, sys) # (3.4) Plot the simulated signal begin signal_t2_star_gre = plot_signal(raw_t2_star_gre; slider=false) - addtraces!(signal_t2_star_gre, trace_decay) + addtraces!(signal_t2_star_gre, t2_decay(t_adc)) signal_t2_star_gre end @@ -344,7 +341,7 @@ raw_t2_star_se = simulate(obj_t2star, seq_se, sys) # (4.4) Compare the signal obtained in (4.6) with the one at (3.5) begin signal_t2_star_se = plot_signal(raw_t2_star_se; slider=false) - addtraces!(signal_t2_star_se, trace_decay) + addtraces!(signal_t2_star_se, t2_decay(t_adc)) relayout!(signal_t2_star_se, signal_layout; title="SE") fig_signal_3 = [signal_gre signal_t2_star_gre signal_t2_star_se] relayout(fig_signal_3, showlegend=false) From 3fde402ca7a7613045f15f2c77564a4f5491fcfb Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Wed, 20 Dec 2023 14:53:17 -0300 Subject: [PATCH 11/15] Compare kspaces in Pluto example --- .../simulation-example-solution.html | 4 +- .../simulation-example-solution.jl | 88 ++++++++++++------- .../simulation-example.html | 4 +- .../simulation-example.jl | 59 ++++++++----- 4 files changed, 99 insertions(+), 56 deletions(-) diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.html b/examples/6.educational_pluto_notebook/simulation-example-solution.html index a381c1a72..23119839b 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.html +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.jl b/examples/6.educational_pluto_notebook/simulation-example-solution.jl index 928f757ba..4ae8b2b58 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.jl +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.jl @@ -25,7 +25,7 @@ using KomaMRI, PlutoPlotly, PlutoUI # ╔═╡ cc66bfed-b61b-4067-8c94-4c54b82a3b42 md""" -These are the versions of KomaMRI and its subpackages. +These are the versions of KomaMRI and their subpackages. """ # ╔═╡ 8529f36d-2d39-4b45-a821-01c8346539fd @@ -174,25 +174,25 @@ plot_seq(seq_gre; slider=false) # ╔═╡ 3abca406-2e6b-4b37-8835-65cfad9d0caa # (2.4) Plot the $k$-space with the `plot_kspace` function -plot_kspace(seq_gre) +kspace_gre = plot_kspace(seq_gre) # ╔═╡ ada602d2-4f4b-4fb4-a763-8a639e05ff38 # (2.5) Simulate the seq_gre sequence raw_gre = simulate(obj, seq_gre, sys) +# ╔═╡ 9a88a54b-bcc7-41ad-8e60-f4d450dccb2d +# (2.7) Reconstruct the 1D image +recon_gre = plot(abs.(KomaMRI.fftc(raw_gre.profiles[1].data))) + # ╔═╡ 41d14dec-b852-4316-aefb-c3d08fa43216 # (2.6) Plot the simulated signal begin - t_adc = range(10.587, 30.587, 100) + t_adc_gre = range(1e3*cumsum([0; seq_gre.DUR])[end-1:end]..., 100) signal_gre = plot_signal(raw_gre; slider=false) - addtraces!(signal_gre, t2_decay(t_adc)) + addtraces!(signal_gre, t2_decay(t_adc_gre)) signal_gre end -# ╔═╡ 9a88a54b-bcc7-41ad-8e60-f4d450dccb2d -# (2.7) Reconstruct the 1D image -recon_gre = plot(abs.(KomaMRI.fftc(raw_gre.profiles[1].data))) - # ╔═╡ 97104c46-e81f-444a-957f-0bbb1b02f1b8 md""" # 3. $T_{2}^{*}$-decay @@ -259,12 +259,12 @@ raw_t2_star_gre = simulate(obj_t2star, seq_gre, sys) # (3.4) Plot the simulated signal begin signal_t2_star_gre = plot_signal(raw_t2_star_gre; slider=false) - addtraces!(signal_t2_star_gre, t2_decay(t_adc)) + addtraces!(signal_t2_star_gre, t2_decay(t_adc_gre)) signal_t2_star_gre end # ╔═╡ 18c82ff1-0bde-4fa0-848c-d0eb73d1ac7c -# (3.5) Compare the plot in (3.5) with (2.6) +# (3.5) Compare the plot in (3.4) with (2.6) begin signal_layout = Layout(yaxis=attr(range=[-5, 16.5])) relayout!(signal_gre, signal_layout; title="GRE-T2") @@ -296,59 +296,68 @@ The spin echo experiment has the advantage that the echo signal amplitud it is m For this section we will use the phantom `obj_t2star` and a new sequence `seq_se`. -- (4.1) Create a sequence called `seq_se` with the following blocks: - * (4.1.1) A 90deg hard RF pulse - * (4.1.2) A `Delay` of $$\mathrm{TE}/2$$ with a positive gradient (area `Ax`) - * (4.1.3) A 180deg hard RF pulse - * (4.1.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in $$\mathrm{TE}$$ - - - (4.2) Plot `seq_se` and its k-space. Is the k-space the same as `seq_gre` in (2.3)? +Our sequence consists of: + - (4.1) A 90deg hard RF pulse + - (4.2) A `Delay` of $$\mathrm{TE}/2$$ with a positive gradient (area `Ax`) + - (4.3) A 180deg hard RF pulse + - (4.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in $$\mathrm{TE}$$ + - (4.5) Create concatenating these blocks into a sequence called `seq_se` + - (4.6) Plot `seq_se` and its k-space. Is the k-space the same as `seq_gre` in (2.3)? """ # ╔═╡ 27e65680-22a0-4079-b6df-d60a3218e52e -# (4.1) Create a Spin Echo sequence `seq_se` +# (4.5) Create concatenating these blocks into a sequence called `seq_se` begin - # (4.1.1) A 90deg hard RF pulse + # (4.1) A 90deg hard RF pulse seq_se = Sequence() seq_se += rf - # (4.1.2) A `Delay` of TE/2 with a positive gradient (area `Ax`) + # (4.2) A `Delay` of TE/2 with a positive gradient (area `Ax`) seq_se += -1*gx_pre - # (4.1.3) A 180deg hard RF pulse + # (4.3) A 180deg hard RF pulse seq_se += (0.0+2.0im)*rf - # (4.1.4) A readout gradient + # (4.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in $$\mathrm{TE}$$ seq_se += readout end # ╔═╡ f1f3b700-5916-496f-b938-46f7f08b4eb6 -# (4.2) Plot seq_se and its k-space. Is the k-space the same as seq_gre in (2.3)? +# (4.6) Plot seq_se and its k-space. Is the k-space the same as seq_gre in (2.3)? plot_seq(seq_se; slider=false) # ╔═╡ 4e1434e1-673f-4206-a271-9edec10ebd6a -plot_kspace(seq_se) +kspace_se = plot_kspace(seq_se) + +# ╔═╡ c02f3898-10cb-4f1e-b5ef-eb42b803baed +begin + relayout!(kspace_gre; title="GRE") + relayout!(kspace_se; title="SE") + fig_kspace = [kspace_gre kspace_se] + relayout(fig_kspace, showlegend=false) +end # ╔═╡ 45952512-aaf1-43d8-a95e-c32bb2633f42 md""" - - (4.3) Simulate using `seq_se` and `obj_t2star` - - (4.4) Compare the signal obtained in (4.6) with the one at (3.5) - - (4.5) Reconstruct the 1D image + - (4.7) Simulate using `seq_se` and `obj_t2star` + - (4.8) Compare the signal obtained in (4.6) with the one at (3.5) + - (4.9) Reconstruct the 1D image """ # ╔═╡ 97479437-9ce3-4b33-9134-0f2af89bccb5 -# (4.3) Simulate using seq_se and obj_t2star +# (4.7) Simulate using seq_se and obj_t2star raw_t2_star_se = simulate(obj_t2star, seq_se, sys) # ╔═╡ 1c79b37e-d4e0-490f-9466-20ce28f017ae -# (4.4) Compare the signal obtained in (4.6) with the one at (3.5) +# (4.8) Compare the signal obtained in (4.7) with the one at (3.4) begin + t_adc_se = range(1e3*cumsum([0; seq_se.DUR])[end-1:end]..., 100) signal_t2_star_se = plot_signal(raw_t2_star_se; slider=false) - addtraces!(signal_t2_star_se, t2_decay(t_adc)) + addtraces!(signal_t2_star_se, t2_decay(t_adc_se)) relayout!(signal_t2_star_se, signal_layout; title="SE") fig_signal_3 = [signal_gre signal_t2_star_gre signal_t2_star_se] relayout(fig_signal_3, showlegend=false) end # ╔═╡ 2e65ae31-f50a-462b-9744-80bf6cdb388e -# (4.5) Reconstruct the 1D image +# (4.9) Reconstruct the 1D image recon_t2_star_se = plot(abs.(KomaMRI.fftc(raw_t2_star_se.profiles[1].data))) # ╔═╡ 34824db7-13c4-45e2-befa-f027b9b585c0 @@ -363,6 +372,20 @@ md""" Congratulations! you finished the simulation hands-on session 🥳! """ +# ╔═╡ ab8dc1ce-d1ef-43a0-9495-dac931b52aec +# Set this boolean to `true` when you finish +activity_finished = true + +# ╔═╡ 58be4150-2b7a-4f9e-a7d7-40a086fd3a53 +if activity_finished + html""" + + """ +end + # ╔═╡ 00000000-0000-0000-0000-000000000001 PLUTO_PROJECT_TOML_CONTENTS = """ [deps] @@ -1970,11 +1993,14 @@ version = "3.0.2+0" # ╠═27e65680-22a0-4079-b6df-d60a3218e52e # ╠═f1f3b700-5916-496f-b938-46f7f08b4eb6 # ╠═4e1434e1-673f-4206-a271-9edec10ebd6a +# ╠═c02f3898-10cb-4f1e-b5ef-eb42b803baed # ╟─45952512-aaf1-43d8-a95e-c32bb2633f42 # ╠═97479437-9ce3-4b33-9134-0f2af89bccb5 # ╠═1c79b37e-d4e0-490f-9466-20ce28f017ae # ╠═2e65ae31-f50a-462b-9744-80bf6cdb388e # ╠═34824db7-13c4-45e2-befa-f027b9b585c0 # ╟─fe8bbcd2-e8f5-4225-80c3-47e73176fb3d +# ╠═ab8dc1ce-d1ef-43a0-9495-dac931b52aec +# ╟─58be4150-2b7a-4f9e-a7d7-40a086fd3a53 # ╟─00000000-0000-0000-0000-000000000001 # ╟─00000000-0000-0000-0000-000000000002 diff --git a/examples/6.educational_pluto_notebook/simulation-example.html b/examples/6.educational_pluto_notebook/simulation-example.html index 6d7b970cf..5107c877a 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.html +++ b/examples/6.educational_pluto_notebook/simulation-example.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example.jl b/examples/6.educational_pluto_notebook/simulation-example.jl index 9b017a36a..2ca83d70a 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.jl +++ b/examples/6.educational_pluto_notebook/simulation-example.jl @@ -25,7 +25,7 @@ using KomaMRI, PlutoPlotly, PlutoUI # ╔═╡ cc66bfed-b61b-4067-8c94-4c54b82a3b42 md""" -These are the versions of KomaMRI and its subpackages. +These are the versions of KomaMRI and their subpackages. """ # ╔═╡ 8529f36d-2d39-4b45-a821-01c8346539fd @@ -226,7 +226,7 @@ md""" # ... # ╔═╡ 18c82ff1-0bde-4fa0-848c-d0eb73d1ac7c -# (3.5) Compare the plot in (3.5) with (2.6) +# (3.5) Compare the plot in (3.4) with (2.6) # ... # ╔═╡ 4a4a6bd3-b820-479c-89e3-f3ce79a316db @@ -243,47 +243,48 @@ The spin echo experiment has the advantage that the echo signal amplitud it is m For this section we will use the phantom `obj_t2star` and a new sequence `seq_se`. -- (4.1) Create a sequence called `seq_se` concatenating the following blocks: - * (4.1.1) A 90deg hard RF pulse - * (4.1.2) A `Delay` of $$\mathrm{TE}/2$$ with a positive gradient (area `Ax`) - * (4.1.3) A 180deg hard RF pulse - * (4.1.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in $$\mathrm{TE}$$ - - - (4.2) Plot `seq_se` and its k-space. Is the k-space the same as `seq_gre` in (2.3)? +Our sequence consists of: + - (4.1) A 90deg hard RF pulse + - (4.2) A `Delay` of $$\mathrm{TE}/2$$ with a positive gradient (area `Ax`) + - (4.3) A 180deg hard RF pulse + - (4.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in $$\mathrm{TE}$$ + - (4.5) Create concatenating these blocks into a sequence called `seq_se` + - (4.6) Plot `seq_se` and its k-space. Is the k-space the same as `seq_gre` in (2.3)? """ # ╔═╡ c8a37593-3028-4e50-ad07-dc81edba45c8 -# (4.1) Create a Spin Echo sequence `seq_se` -# (4.1.1) A 90deg hard RF pulse +# (4.1) A 90deg hard RF pulse # ... -# (4.1.2) A `Delay` of TE/2 with a positive gradient (area `Ax`) +# (4.2) A `Delay` of TE/2 with a positive gradient (area `Ax`) # ... -# (4.1.3) A 180deg hard RF pulse +# (4.3) A 180deg hard RF pulse # ... -# (4.1.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in TE +# (4.4) A readout gradient of area `2Ax` with an ADC (similar to (2.2)), such that the middle of the gradient and ADC are in $$\mathrm{TE}$$ +# ... +# (4.5) Create concatenating these blocks into a sequence called `seq_se` # ... # ╔═╡ f1f3b700-5916-496f-b938-46f7f08b4eb6 -# (4.2) Plot seq_se and its k-space. Is the k-space the same as seq_gre in (2.3)? +# (4.6) Plot seq_se and its k-space. Is the k-space the same as seq_gre in (2.3)? # ... # ╔═╡ 45952512-aaf1-43d8-a95e-c32bb2633f42 md""" - - (4.3) Simulate using `seq_se` and `obj_t2star` - - (4.4) Compare the signal obtained in (4.6) with the one at (3.5) - - (4.5) Reconstruct the 1D image + - (4.7) Simulate using `seq_se` and `obj_t2star` + - (4.8) Compare the signal obtained in (4.6) with the one at (3.5) + - (4.9) Reconstruct the 1D image """ # ╔═╡ 97479437-9ce3-4b33-9134-0f2af89bccb5 -# (4.3) Simulate using seq_se and obj_t2star +# (4.7) Simulate using seq_se and obj_t2star # ... # ╔═╡ 1c79b37e-d4e0-490f-9466-20ce28f017ae -# (4.4) Compare the signal obtained in (4.6) with the one at (3.5) +# (4.8) Compare the signal obtained in (4.7) with the one at (3.4) # ... # ╔═╡ 2e65ae31-f50a-462b-9744-80bf6cdb388e -# (4.5) Reconstruct the 1D image +# (4.9) Reconstruct the 1D image # ... # ╔═╡ fe8bbcd2-e8f5-4225-80c3-47e73176fb3d @@ -291,6 +292,20 @@ md""" Congratulations! you finished the simulation hands-on session 🥳! """ +# ╔═╡ e826311e-4d85-4d52-9107-a54f1cb1e004 +# Set this boolean to `true` when you finish +activity_finished = false + +# ╔═╡ 824a814d-8bfd-4754-9b4c-317fd3ebad86 +if activity_finished + html""" + + """ +end + # ╔═╡ 00000000-0000-0000-0000-000000000001 PLUTO_PROJECT_TOML_CONTENTS = """ [deps] @@ -1902,5 +1917,7 @@ version = "3.0.2+0" # ╠═1c79b37e-d4e0-490f-9466-20ce28f017ae # ╠═2e65ae31-f50a-462b-9744-80bf6cdb388e # ╟─fe8bbcd2-e8f5-4225-80c3-47e73176fb3d +# ╠═e826311e-4d85-4d52-9107-a54f1cb1e004 +# ╟─824a814d-8bfd-4754-9b4c-317fd3ebad86 # ╟─00000000-0000-0000-0000-000000000001 # ╟─00000000-0000-0000-0000-000000000002 From 1b1e5f3d71a7e9f5cd135f14ac9ad9409722a5e9 Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Wed, 20 Dec 2023 16:23:15 -0300 Subject: [PATCH 12/15] Use get_adc_sampling_times() function in Pluto example --- .../simulation-example-solution.html | 4 ++-- .../simulation-example-solution.jl | 8 ++++---- .../6.educational_pluto_notebook/simulation-example.html | 4 ++-- .../6.educational_pluto_notebook/simulation-example.jl | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.html b/examples/6.educational_pluto_notebook/simulation-example-solution.html index 23119839b..3bbcce5a4 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.html +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.jl b/examples/6.educational_pluto_notebook/simulation-example-solution.jl index 4ae8b2b58..ea43d2473 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.jl +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.jl @@ -25,7 +25,7 @@ using KomaMRI, PlutoPlotly, PlutoUI # ╔═╡ cc66bfed-b61b-4067-8c94-4c54b82a3b42 md""" -These are the versions of KomaMRI and their subpackages. +These are the versions of KomaMRI and its subpackages. """ # ╔═╡ 8529f36d-2d39-4b45-a821-01c8346539fd @@ -187,7 +187,7 @@ recon_gre = plot(abs.(KomaMRI.fftc(raw_gre.profiles[1].data))) # ╔═╡ 41d14dec-b852-4316-aefb-c3d08fa43216 # (2.6) Plot the simulated signal begin - t_adc_gre = range(1e3*cumsum([0; seq_gre.DUR])[end-1:end]..., 100) + t_adc_gre = KomaMRICore.get_adc_sampling_times(seq_gre)*1e3 signal_gre = plot_signal(raw_gre; slider=false) addtraces!(signal_gre, t2_decay(t_adc_gre)) signal_gre @@ -296,7 +296,7 @@ The spin echo experiment has the advantage that the echo signal amplitud it is m For this section we will use the phantom `obj_t2star` and a new sequence `seq_se`. -Our sequence consists of: +For this sequence we will need: - (4.1) A 90deg hard RF pulse - (4.2) A `Delay` of $$\mathrm{TE}/2$$ with a positive gradient (area `Ax`) - (4.3) A 180deg hard RF pulse @@ -348,7 +348,7 @@ raw_t2_star_se = simulate(obj_t2star, seq_se, sys) # ╔═╡ 1c79b37e-d4e0-490f-9466-20ce28f017ae # (4.8) Compare the signal obtained in (4.7) with the one at (3.4) begin - t_adc_se = range(1e3*cumsum([0; seq_se.DUR])[end-1:end]..., 100) + t_adc_se = KomaMRICore.get_adc_sampling_times(seq_se)*1e3 signal_t2_star_se = plot_signal(raw_t2_star_se; slider=false) addtraces!(signal_t2_star_se, t2_decay(t_adc_se)) relayout!(signal_t2_star_se, signal_layout; title="SE") diff --git a/examples/6.educational_pluto_notebook/simulation-example.html b/examples/6.educational_pluto_notebook/simulation-example.html index 5107c877a..143185b39 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.html +++ b/examples/6.educational_pluto_notebook/simulation-example.html @@ -3,11 +3,11 @@ diff --git a/examples/6.educational_pluto_notebook/simulation-example.jl b/examples/6.educational_pluto_notebook/simulation-example.jl index 2ca83d70a..2344bce2d 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.jl +++ b/examples/6.educational_pluto_notebook/simulation-example.jl @@ -25,7 +25,7 @@ using KomaMRI, PlutoPlotly, PlutoUI # ╔═╡ cc66bfed-b61b-4067-8c94-4c54b82a3b42 md""" -These are the versions of KomaMRI and their subpackages. +These are the versions of KomaMRI and its subpackages. """ # ╔═╡ 8529f36d-2d39-4b45-a821-01c8346539fd @@ -243,7 +243,7 @@ The spin echo experiment has the advantage that the echo signal amplitud it is m For this section we will use the phantom `obj_t2star` and a new sequence `seq_se`. -Our sequence consists of: +For this sequence we will need: - (4.1) A 90deg hard RF pulse - (4.2) A `Delay` of $$\mathrm{TE}/2$$ with a positive gradient (area `Ax`) - (4.3) A 180deg hard RF pulse From 1625e8679eb109bb5c212bf46022bea741556c8e Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Wed, 20 Dec 2023 17:00:12 -0300 Subject: [PATCH 13/15] Allow to download Pluto example from html --- .../simulation-example-solution.html | 10 +++++----- .../simulation-example-solution.jl | 2 +- .../simulation-example.html | 10 +++++----- .../6.educational_pluto_notebook/simulation-example.jl | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.html b/examples/6.educational_pluto_notebook/simulation-example-solution.html index 3bbcce5a4..e3922b158 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.html +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.html @@ -1,15 +1,15 @@ - -
\ No newline at end of file +
\ No newline at end of file diff --git a/examples/6.educational_pluto_notebook/simulation-example-solution.jl b/examples/6.educational_pluto_notebook/simulation-example-solution.jl index ea43d2473..af1957c23 100644 --- a/examples/6.educational_pluto_notebook/simulation-example-solution.jl +++ b/examples/6.educational_pluto_notebook/simulation-example-solution.jl @@ -1,5 +1,5 @@ ### A Pluto.jl notebook ### -# v0.19.32 +# v0.19.36 using Markdown using InteractiveUtils diff --git a/examples/6.educational_pluto_notebook/simulation-example.html b/examples/6.educational_pluto_notebook/simulation-example.html index 143185b39..d6a06a331 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.html +++ b/examples/6.educational_pluto_notebook/simulation-example.html @@ -1,15 +1,15 @@ - -
\ No newline at end of file +
\ No newline at end of file diff --git a/examples/6.educational_pluto_notebook/simulation-example.jl b/examples/6.educational_pluto_notebook/simulation-example.jl index 2344bce2d..c589d1c4b 100644 --- a/examples/6.educational_pluto_notebook/simulation-example.jl +++ b/examples/6.educational_pluto_notebook/simulation-example.jl @@ -1,5 +1,5 @@ ### A Pluto.jl notebook ### -# v0.19.32 +# v0.19.36 using Markdown using InteractiveUtils From de0d3150467e10cd1db94effc6c2e288a613f6ee Mon Sep 17 00:00:00 2001 From: beorostica-asusFX505GT-win Date: Wed, 20 Dec 2023 17:18:49 -0300 Subject: [PATCH 14/15] Update Pluto example title [skip ci] --- docs/make.jl | 2 +- docs/src/pluto-simulation.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index 03d691c14..ef1193cd5 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -64,7 +64,7 @@ makedocs( #"Sequence Definition" => "sequence.md"; #"Events Definition" => "events.md"; "Examples" => literate_examples; - "Educational Material" => "pluto-simulation.md"; + "Educational Material 📚" => "pluto-simulation.md"; "Simulation" => "mri-theory.md"; "API Documentation" => "api.md"; ], diff --git a/docs/src/pluto-simulation.md b/docs/src/pluto-simulation.md index 16ee7f036..19ca2301d 100644 --- a/docs/src/pluto-simulation.md +++ b/docs/src/pluto-simulation.md @@ -1,4 +1,4 @@ -# My first MRI simulations: FID, GE, and SE +# 1D Simulations This example was used in the workshop [MRI: Processing your own data](https://github.com/LIBREhub/MRI-processing-2023). In the workshop's GitHub you'll find: - A presentation on [open-source software](https://github.com/LIBREhub/MRI-processing-2023/blob/main/02-simulation/day1_OpenSoftware_Nov2023.pdf) From d14b8a90d654bbf300dd8ee2a18dc9fec5967d12 Mon Sep 17 00:00:00 2001 From: Carlos Castillo Passi Date: Wed, 20 Dec 2023 17:20:19 -0300 Subject: [PATCH 15/15] Update docs/src/pluto-simulation.md [skip ci] --- docs/src/pluto-simulation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/pluto-simulation.md b/docs/src/pluto-simulation.md index 19ca2301d..ef7be032d 100644 --- a/docs/src/pluto-simulation.md +++ b/docs/src/pluto-simulation.md @@ -1,4 +1,4 @@ -# 1D Simulations +# 1D Simulations: FID, GE, and SE This example was used in the workshop [MRI: Processing your own data](https://github.com/LIBREhub/MRI-processing-2023). In the workshop's GitHub you'll find: - A presentation on [open-source software](https://github.com/LIBREhub/MRI-processing-2023/blob/main/02-simulation/day1_OpenSoftware_Nov2023.pdf)