From 0e6e58330a154c7ef4cc4ca26919ade3a72dd441 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Tue, 3 Dec 2024 09:31:49 +0000 Subject: [PATCH] build based on bb95ebc --- dev/.documenter-siteinfo.json | 2 +- dev/api/index.html | 12 ++++++------ dev/building_basis/index.html | 8 ++++---- dev/convert/index.html | 2 +- dev/fit_T2/index.html | 2 +- dev/generated/examples/subspace_julia_epg.ipynb | 5 ++++- dev/generated/examples/subspace_julia_epg/index.html | 7 +++++-- dev/index.html | 2 +- dev/installation/index.html | 2 +- dev/reconstruction_subspace/index.html | 2 +- dev/search_index.js | 2 +- 11 files changed, 26 insertions(+), 20 deletions(-) diff --git a/dev/.documenter-siteinfo.json b/dev/.documenter-siteinfo.json index d2b50d4..3b684dc 100644 --- a/dev/.documenter-siteinfo.json +++ b/dev/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.11.2","generation_timestamp":"2024-12-02T19:35:00","documenter_version":"1.3.0"}} \ No newline at end of file +{"documenter":{"julia_version":"1.11.2","generation_timestamp":"2024-12-03T09:31:45","documenter_version":"1.3.0"}} \ No newline at end of file diff --git a/dev/api/index.html b/dev/api/index.html index 4587808..949f77e 100644 --- a/dev/api/index.html +++ b/dev/api/index.html @@ -1,11 +1,11 @@ -API · Subspace_MESE.jl
Subspace_MESE.MESE_EPGMethod
MESE_EPG(T2::Ty,T1::Ty,TE::Ty,TR::Ty,ETL::Int,delta::Ty,dummy::Int) where Ty <: AbstractFloat
+API · Subspace_MESE.jl
Subspace_MESE.MESE_EPGMethod
MESE_EPG(T2::Ty,T1::Ty,TE::Ty,TR::Ty,ETL::Int,delta::Ty,dummy::Int) where Ty <: AbstractFloat
 
 Generate the signal evolution of a Multi-Echo Spin-Echo sequence with an Extended Phase Graph model.

Input :

- `T2` : Transverse relaxation
 - `T1` : Longitudinal relaxation
 - `TE` : Echo Time
 - `TR` : Repetition time
-- `ETL` : Echo Train Length

Output :

- Amplitude of each echoes
source
Subspace_MESE.MESE_basis_EPGFunction
MESE_basis_EPG(NUM_BASIS::Int,TE,ETL::Int,T2_vec::Union{AbstractVector,AbstractFloat},B1_vec::Union{AbstractVector,AbstractFloat} = 1.0,T1_vec::Union{AbstractVector,AbstractFloat}=1000.0;TR = 1000.0,dummy::Int = 3)
+- `ETL` : Echo Train Length

Output :

- Amplitude of each echoes
source
Subspace_MESE.MESE_basis_EPGFunction
MESE_basis_EPG(NUM_BASIS::Int,TE,ETL::Int,T2_vec::Union{AbstractVector,AbstractFloat},B1_vec::Union{AbstractVector,AbstractFloat} = 1.0,T1_vec::Union{AbstractVector,AbstractFloat}=1000.0;TR = 1000.0,dummy::Int = 3)
 
 Generate a temporal basis for a Multi-Echo Spin-Echo sequence with an Extended Phase Graph model for various value of T2/B1/T1

stored as a vector in T2_vec/B1_vec/T1_vec.

Input :

- `NUM_BASIS::Int : Number of temporal basis to extract
 - `TE::AbstractFloat` : Cartesian acquisition with a fully-sampled center.
@@ -23,7 +23,7 @@
 ETL = 50
 NUM_BASIS = 6
 
-basis_epg, epg_dict =MESE_basis_EPG(NUM_BASIS,TE,ETL,T2_vec,B1_vec,T1_vec;TR=TR,dummy=dummy)
source
Subspace_MESE.MESE_basis_expMethod
    MESE_basis_exp(NUM_BASIS::Int,TE::AbstractFloat,ETL::Int, T2_vec::AbstractVector;removeFirstPoint::Bool=false)

Generate a temporal basis for a Multi-Echo Spin-Echo sequence with an exponential model.for various value of T2 stored as a vector in T2_vec. The first point of the echo train can be removed from the dictionnary with the keyword removeFirstPoint to minimize the effect of stimulated echoes.

Input :

- `NUM_BASIS::Int : Number of temporal basis to extract
+basis_epg, epg_dict =MESE_basis_EPG(NUM_BASIS,TE,ETL,T2_vec,B1_vec,T1_vec;TR=TR,dummy=dummy)
source
Subspace_MESE.MESE_basis_expMethod
    MESE_basis_exp(NUM_BASIS::Int,TE::AbstractFloat,ETL::Int, T2_vec::AbstractVector;removeFirstPoint::Bool=false)

Generate a temporal basis for a Multi-Echo Spin-Echo sequence with an exponential model.for various value of T2 stored as a vector in T2_vec. The first point of the echo train can be removed from the dictionnary with the keyword removeFirstPoint to minimize the effect of stimulated echoes.

Input :

- `NUM_BASIS::Int : Number of temporal basis to extract
 - `TE::AbstractFloat` : Cartesian acquisition with a fully-sampled center.
 - `ETL::Int` : Echo Train Length
 - `T2_vec::AbstractVector` : Vector of T₂ values used to generate the signal dictionnary

Keyword :

- `removeFirstPoint::Bool=False` : Remove the first point of the dictionnary before the svd

Output :

- `basis` : Matrix of size (ETL,NUM_BASIS)
@@ -32,7 +32,7 @@
 ETL = 50
 NUM_BASIS = 6
 
-basis_exp,exp_dict = MESE_basis_exp(NUM_BASIS,TE,ETL,T2_vec)
source
Subspace_MESE.RawAcquisitionData_MESEMethod
RawAcquisitionData_MESE(b::BrukerFile)

Convert a Bruker dataset acquired with the aMESECS sequence into a RawAcquisitionData object compatible with the MRIReco functions.

Input : - b::BrukerFile

Output : - raw::RawAcquisitionData

source
Subspace_MESE.RawAcquisitionData_MESE_PV360Method
RawAcquisitionData_MESE_PV360(b::BrukerFile)

Convert a Bruker dataset acquired with the aMESECS_360 sequence into a RawAcquisitionData object compatible with the MRIReco functions.

Input : - b::BrukerFile

Output : - raw::RawAcquisitionData

source
Subspace_MESE.RawAcquisitionData_MESE_PV6Method
RawAcquisitionData_MESE_PV6(b::BrukerFile)

Convert a Bruker dataset acquired with the aMESECS sequence into a RawAcquisitionData object compatible with the MRIReco functions.

Input : - b::BrukerFile

Output : - raw::RawAcquisitionData

source
Subspace_MESE.T2Fit_epg_noiseMethod
T2Fit_epg_noise(ima::Array{T,N}, t::AbstractVector{T},T1=1000.0,TE=7.0; EPGthresh = 1e-5,p0=nothing,mask = nothing) where {T<:Real,N}

WIP

source
Subspace_MESE.T2Fit_exp_noiseMethod
    T2Fit_exp_noise(ima::Array{T,N}, t::AbstractVector{T}; removePoint::Bool=true, L::Int=1, mask = nothing) where {T<:Real,N}

Fit the relaxation parameters T2 with the equation : $S(t) = \sqrt{(M_0 \exp(-\frac{t}{T2}))^2 + 2 L \sigma_g^2}$ where L est le nombre de canaux, et $\sigma_g$ le bruit gaussien sur les image

Arguments

  • ima::Array{T,N}: multi-dimensionnal images. Last dimension stores the temporal dimension
  • t::AbstractVector{<:Real}: times vector in ms
  • p0=nothing: starting values for fit, if empty p0=[maximum(ima),30,maximum(ima)*0.1]

Keywords

  • removePoint::Bool=true: remove the first point before fitting
  • L::Int=1: Number of coil elements
  • mask::

Returns

  • fit_params : parameter maps last dimension stores the following maps (M₀ , T₂ , σ)

Bibliography

  • Cárdenas-Blanco A, Tejos C, Irarrazaval P, Cameron I. Noise in magnitude magnetic

resonance images. Concepts Magn Reson Part A [Internet]. 2008 Nov;32A(6):409?16. Available from: http://doi.wiley.com/10.1002/cmr.a.20124

  • Feng Y, He T, Gatehouse PD, Li X, Harith Alam M, Pennell DJ, et al. Improved MRI R 2 *

relaxometry of iron-loaded liver with noise correction. Magn Reson Med [Internet]. 2013 Dec;70(6):1765?74. Available from: http://doi.wiley.com/10.1002/mrm.24607

source
Subspace_MESE.basis_calibrationMethod
basis_calibration(NUM_BASIS::Int,acq::AcquisitionData{T,D},crop_size::NTuple{D,Int}) where {T,D}

k_bart = kDataCart(acq);

Extract a temporal basis from a low-resolution images reconstructed using a fully sampled area at the center of the k-space with a size crop_size.

Input :

- `NUM_BASIS::Int : Number of temporal basis to extract
+basis_exp,exp_dict = MESE_basis_exp(NUM_BASIS,TE,ETL,T2_vec)
source
Subspace_MESE.RawAcquisitionData_MESEMethod
RawAcquisitionData_MESE(b::BrukerFile)

Convert a Bruker dataset acquired with the aMESECS sequence into a RawAcquisitionData object compatible with the MRIReco functions.

Input : - b::BrukerFile

Output : - raw::RawAcquisitionData

source
Subspace_MESE.RawAcquisitionData_MESE_PV360Method
RawAcquisitionData_MESE_PV360(b::BrukerFile)

Convert a Bruker dataset acquired with the aMESECS_360 sequence into a RawAcquisitionData object compatible with the MRIReco functions.

Input : - b::BrukerFile

Output : - raw::RawAcquisitionData

source
Subspace_MESE.RawAcquisitionData_MESE_PV6Method
RawAcquisitionData_MESE_PV6(b::BrukerFile)

Convert a Bruker dataset acquired with the aMESECS sequence into a RawAcquisitionData object compatible with the MRIReco functions.

Input : - b::BrukerFile

Output : - raw::RawAcquisitionData

source
Subspace_MESE.T2Fit_epg_noiseMethod
T2Fit_epg_noise(ima::Array{T,N}, t::AbstractVector{T},T1=1000.0,TE=7.0; EPGthresh = 1e-5,p0=nothing,mask = nothing) where {T<:Real,N}

WIP

source
Subspace_MESE.T2Fit_exp_noiseMethod
    T2Fit_exp_noise(ima::Array{T,N}, t::AbstractVector{T}; removePoint::Bool=true, L::Int=1, mask = nothing) where {T<:Real,N}

Fit the relaxation parameters T2 with the equation : $S(t) = \sqrt{(M_0 \exp(-\frac{t}{T2}))^2 + 2 L \sigma_g^2}$ where L est le nombre de canaux, et $\sigma_g$ le bruit gaussien sur les image

Arguments

  • ima::Array{T,N}: multi-dimensionnal images. Last dimension stores the temporal dimension
  • t::AbstractVector{<:Real}: times vector in ms
  • p0=nothing: starting values for fit, if empty p0=[maximum(ima),30,maximum(ima)*0.1]

Keywords

  • removePoint::Bool=true: remove the first point before fitting
  • L::Int=1: Number of coil elements
  • mask::

Returns

  • fit_params : parameter maps last dimension stores the following maps (M₀ , T₂ , σ)

Bibliography

  • Cárdenas-Blanco A, Tejos C, Irarrazaval P, Cameron I. Noise in magnitude magnetic

resonance images. Concepts Magn Reson Part A [Internet]. 2008 Nov;32A(6):409?16. Available from: http://doi.wiley.com/10.1002/cmr.a.20124

  • Feng Y, He T, Gatehouse PD, Li X, Harith Alam M, Pennell DJ, et al. Improved MRI R 2 *

relaxometry of iron-loaded liver with noise correction. Magn Reson Med [Internet]. 2013 Dec;70(6):1765?74. Available from: http://doi.wiley.com/10.1002/mrm.24607

source
Subspace_MESE.basis_calibrationMethod
basis_calibration(NUM_BASIS::Int,acq::AcquisitionData{T,D},crop_size::NTuple{D,Int}) where {T,D}

k_bart = kDataCart(acq);

Extract a temporal basis from a low-resolution images reconstructed using a fully sampled area at the center of the k-space with a size crop_size.

Input :

- `NUM_BASIS::Int : Number of temporal basis to extract
 - `acq::AcquisitionData` : Cartesian acquisition with a fully-sampled center.
 - `crop_size::NTuple{D,Int})` : size of the  central part of k-space used

Output :

- `basis` : Matrix of size (ETL,NUM_BASIS)
 - `calib_dict` : Dictionnary of signal used to generate the basis

Example :

b = BrukerFile("path/to/dataset")
@@ -40,7 +40,7 @@
 raw = RawAcquisitionData_MESE(b)
 acq = AcquisitionData(raw,OffsetBruker = true);
 
-basis, calib_dict = MESE_basis_calibration(acq,(15,15,15),6)
source
Subspace_MESE.subspace_bart_reconstructionMethod
subspace_bart_reconstruction(acq::AcquisitionData,params::Dict{Symbol,Any},bart_path::AbstractString)

Reconstruction of the accelerated MESE sequence with BART.

Input :

- `acq::AcquisitionData` : Cartesian acquisition with a fully-sampled center.
+basis, calib_dict = MESE_basis_calibration(acq,(15,15,15),6)
source
Subspace_MESE.subspace_bart_reconstructionMethod
subspace_bart_reconstruction(acq::AcquisitionData,params::Dict{Symbol,Any},bart_path::AbstractString)

Reconstruction of the accelerated MESE sequence with BART.

Input :

- `acq::AcquisitionData` : Cartesian acquisition with a fully-sampled center.
 - `params::Dict{Symbol,Any}` : size of the  central part of k-space used
 - `bart_path::AbstractString` : path to the BART executable library

Output :

- `basis` : Matrix of size (ETL,NUM_BASIS)
 - `calib_dict` : Dictionnary of signal used to generate the basis

Example :

b = BrukerFile("path/to/dataset")
@@ -48,4 +48,4 @@
 raw = RawAcquisitionData_MESE(b)
 acq = AcquisitionData(raw,OffsetBruker = true);
 
-basis, calib_dict = MESE_basis_calibration(acq,(15,15,15),6)
source
+basis, calib_dict = MESE_basis_calibration(acq,(15,15,15),6)
source
diff --git a/dev/building_basis/index.html b/dev/building_basis/index.html index d6fcfc4..d160e73 100644 --- a/dev/building_basis/index.html +++ b/dev/building_basis/index.html @@ -8,7 +8,7 @@ ETL = 50 NUM_BASIS = 6 -basis_exp,exp_dict = MESE_basis_exp(NUM_BASIS,TE,ETL,T2_vec)source

In the publication, the subspace is extracted from a dictionary generated with a range of $T_2$ from 1 ms to 2000 ms with a step of 1 ms.

Other approachs can be used :

Let's take a look at the first 6 subspace vectors from a linear repartition :

using Subspace_MESE
+basis_exp,exp_dict = MESE_basis_exp(NUM_BASIS,TE,ETL,T2_vec)
source

In the publication, the subspace is extracted from a dictionary generated with a range of $T_2$ from 1 ms to 2000 ms with a step of 1 ms.

Other approachs can be used :

Let's take a look at the first 6 subspace vectors from a linear repartition :

using Subspace_MESE
 
 T2_vec = 1.0:1.0:2000.0
 TE = 7.0
@@ -44,7 +44,7 @@
 ETL = 50
 NUM_BASIS = 6
 
-basis_epg, epg_dict =MESE_basis_EPG(NUM_BASIS,TE,ETL,T2_vec,B1_vec,T1_vec;TR=TR,dummy=dummy)
source

In order to generate the EPG subspace, more parameters need to be defined. Specifically, the range of $B_1$ to be expected in the acquisition might be larger for surfacic transmit coil than for volumic coils that have a homogeneous $B_1^+$ field.

Of note, B1vec, T2vec, T1vec can also be passed as float values rather than vectors. In the publication, the T1vec was fixed to 1000 ms.

using Subspace_MESE
+basis_epg, epg_dict =MESE_basis_EPG(NUM_BASIS,TE,ETL,T2_vec,B1_vec,T1_vec;TR=TR,dummy=dummy)
source

In order to generate the EPG subspace, more parameters need to be defined. Specifically, the range of $B_1$ to be expected in the acquisition might be larger for surfacic transmit coil than for volumic coils that have a homogeneous $B_1^+$ field.

Of note, B1vec, T2vec, T1vec can also be passed as float values rather than vectors. In the publication, the T1vec was fixed to 1000 ms.

using Subspace_MESE
 B1_vec = 0.8:0.01:1.0
 T2_vec = 1.0:1.0:2000.0
 T1_vec = 1000.0 #can also be a vector of float
@@ -73,9 +73,9 @@
 raw = RawAcquisitionData_MESE(b)
 acq = AcquisitionData(raw,OffsetBruker = true);
 
-basis, calib_dict = MESE_basis_calibration(acq,(15,15,15),6)
source

The calibration subspace reconstructs low-resolution images from a fully sampled area of the k-space.

You can generate the subspace from the acquired accelerated acquisition with the parameter crop_size equal to the size of the fully sampled area of the k-space.

But you can also generate the subspace from a different fully acquisition (for example on a control acquisition)

b = BrukerFile("path/to/dataset")
+basis, calib_dict = MESE_basis_calibration(acq,(15,15,15),6)
source

The calibration subspace reconstructs low-resolution images from a fully sampled area of the k-space.

You can generate the subspace from the acquired accelerated acquisition with the parameter crop_size equal to the size of the fully sampled area of the k-space.

But you can also generate the subspace from a different fully acquisition (for example on a control acquisition)

b = BrukerFile("path/to/dataset")
 
 raw = RawAcquisitionData_MESE(b)
 acq = AcquisitionData(raw,OffsetBruker = true);
 
-basis,_ = MESE_basis_calibration(acq,(15,15,15),6)
+basis,_ = MESE_basis_calibration(acq,(15,15,15),6) diff --git a/dev/convert/index.html b/dev/convert/index.html index fb14942..2af4d88 100644 --- a/dev/convert/index.html +++ b/dev/convert/index.html @@ -9,4 +9,4 @@ params[:reco] = "direct" im_u = reconstruction(acq, params);

This returns images which can be artifacted in the case of an undersampled acquisitioncan.

We can combine the different coil elements with a sum of squares :

using Subspace_MESE.MRICoilSensitivities
-im_u_sos = mergeChannels(im_u)
+im_u_sos = mergeChannels(im_u) diff --git a/dev/fit_T2/index.html b/dev/fit_T2/index.html index 45b1ab8..e2c425e 100644 --- a/dev/fit_T2/index.html +++ b/dev/fit_T2/index.html @@ -1,2 +1,2 @@ -T₂ mapping · Subspace_MESE.jl

Fitting the data

The reconstruction and the fitting parts are totally independent.

The fitting functions expect a multidimensionnal-array with the echoes along the last dimension. The images should not be in complex, remember to use abs.(img).

Exponential $T_2$ fitting + noise

In the publication we used an analytical model to fit the exponential decay of the echoes :

\[S(t) = \sqrt{\left(M_0 \ exp(-\frac{t}{T_2})\right)^2 + 2 \ L \ \sigma_g^2}\]

where L is the number of coil and $\sigma_g$ corresponds to the gaussian noise level on the image.

You can perform this fit with the following function :

Subspace_MESE.T2Fit_exp_noiseFunction
    T2Fit_exp_noise(ima::Array{T,N}, t::AbstractVector{T}; removePoint::Bool=true, L::Int=1, mask = nothing) where {T<:Real,N}

Fit the relaxation parameters T2 with the equation : $S(t) = \sqrt{(M_0 \exp(-\frac{t}{T2}))^2 + 2 L \sigma_g^2}$ where L est le nombre de canaux, et $\sigma_g$ le bruit gaussien sur les image

Arguments

  • ima::Array{T,N}: multi-dimensionnal images. Last dimension stores the temporal dimension
  • t::AbstractVector{<:Real}: times vector in ms
  • p0=nothing: starting values for fit, if empty p0=[maximum(ima),30,maximum(ima)*0.1]

Keywords

  • removePoint::Bool=true: remove the first point before fitting
  • L::Int=1: Number of coil elements
  • mask::

Returns

  • fit_params : parameter maps last dimension stores the following maps (M₀ , T₂ , σ)

Bibliography

  • Cárdenas-Blanco A, Tejos C, Irarrazaval P, Cameron I. Noise in magnitude magnetic

resonance images. Concepts Magn Reson Part A [Internet]. 2008 Nov;32A(6):409?16. Available from: http://doi.wiley.com/10.1002/cmr.a.20124

  • Feng Y, He T, Gatehouse PD, Li X, Harith Alam M, Pennell DJ, et al. Improved MRI R 2 *

relaxometry of iron-loaded liver with noise correction. Magn Reson Med [Internet]. 2013 Dec;70(6):1765?74. Available from: http://doi.wiley.com/10.1002/mrm.24607

source

The keyword removePoint can be used to delete the first point in the TE vector as well as the first temporal volume in order to reduce the sensitivity of the fit to the stimulated echo.

EPG $T_2$ fitting + noise (WIP)

Another possibility is to fit the equation with an EPG model that, in addition to $M_0$/$T_2$/$\sigma$, also fits the $B_1$ field.

With the current implementation, the fit is not robust enough and also takes too long to use on a 3D volume.

T2Fit_epg_noise
+T₂ mapping · Subspace_MESE.jl

Fitting the data

The reconstruction and the fitting parts are totally independent.

The fitting functions expect a multidimensionnal-array with the echoes along the last dimension. The images should not be in complex, remember to use abs.(img).

Exponential $T_2$ fitting + noise

In the publication we used an analytical model to fit the exponential decay of the echoes :

\[S(t) = \sqrt{\left(M_0 \ exp(-\frac{t}{T_2})\right)^2 + 2 \ L \ \sigma_g^2}\]

where L is the number of coil and $\sigma_g$ corresponds to the gaussian noise level on the image.

You can perform this fit with the following function :

Subspace_MESE.T2Fit_exp_noiseFunction
    T2Fit_exp_noise(ima::Array{T,N}, t::AbstractVector{T}; removePoint::Bool=true, L::Int=1, mask = nothing) where {T<:Real,N}

Fit the relaxation parameters T2 with the equation : $S(t) = \sqrt{(M_0 \exp(-\frac{t}{T2}))^2 + 2 L \sigma_g^2}$ where L est le nombre de canaux, et $\sigma_g$ le bruit gaussien sur les image

Arguments

  • ima::Array{T,N}: multi-dimensionnal images. Last dimension stores the temporal dimension
  • t::AbstractVector{<:Real}: times vector in ms
  • p0=nothing: starting values for fit, if empty p0=[maximum(ima),30,maximum(ima)*0.1]

Keywords

  • removePoint::Bool=true: remove the first point before fitting
  • L::Int=1: Number of coil elements
  • mask::

Returns

  • fit_params : parameter maps last dimension stores the following maps (M₀ , T₂ , σ)

Bibliography

  • Cárdenas-Blanco A, Tejos C, Irarrazaval P, Cameron I. Noise in magnitude magnetic

resonance images. Concepts Magn Reson Part A [Internet]. 2008 Nov;32A(6):409?16. Available from: http://doi.wiley.com/10.1002/cmr.a.20124

  • Feng Y, He T, Gatehouse PD, Li X, Harith Alam M, Pennell DJ, et al. Improved MRI R 2 *

relaxometry of iron-loaded liver with noise correction. Magn Reson Med [Internet]. 2013 Dec;70(6):1765?74. Available from: http://doi.wiley.com/10.1002/mrm.24607

source

The keyword removePoint can be used to delete the first point in the TE vector as well as the first temporal volume in order to reduce the sensitivity of the fit to the stimulated echo.

EPG $T_2$ fitting + noise (WIP)

Another possibility is to fit the equation with an EPG model that, in addition to $M_0$/$T_2$/$\sigma$, also fits the $B_1$ field.

With the current implementation, the fit is not robust enough and also takes too long to use on a 3D volume.

T2Fit_epg_noise
diff --git a/dev/generated/examples/subspace_julia_epg.ipynb b/dev/generated/examples/subspace_julia_epg.ipynb index e8c5ecf..fdac35f 100644 --- a/dev/generated/examples/subspace_julia_epg.ipynb +++ b/dev/generated/examples/subspace_julia_epg.ipynb @@ -119,7 +119,10 @@ "outputs": [], "cell_type": "code", "source": [ - "coilsens = espirit(acq,eigThresh_2=0.0);" + "ncalib = parse.(Int,b[\"CenterMaskSize\"])\n", + "ncalib > 24 ? ncalib = 24 : nothing\n", + "\n", + "coilsens = espirit(acq,eigThresh_2 = 0,(6,6,6),ncalib);" ], "metadata": {}, "execution_count": null diff --git a/dev/generated/examples/subspace_julia_epg/index.html b/dev/generated/examples/subspace_julia_epg/index.html index ffc56a1..a393f09 100644 --- a/dev/generated/examples/subspace_julia_epg/index.html +++ b/dev/generated/examples/subspace_julia_epg/index.html @@ -19,7 +19,10 @@ raw = RawAcquisitionData_MESE(b) acq = AcquisitionData(raw,OffsetBruker = true); -nothing #hide

Estimate the coil sensitivity map with espirit

coilsens = espirit(acq,eigThresh_2=0.0);
+nothing #hide

Estimate the coil sensitivity map with espirit

ncalib = parse.(Int,b["CenterMaskSize"])
+ncalib > 24 ? ncalib = 24 : nothing
+
+coilsens = espirit(acq,eigThresh_2 = 0,(6,6,6),ncalib);
 nothing #hide

Direct reconstruction of undersampled acquisition

params = Dict{Symbol,Any}()
 params[:reconSize] = acq.encodingSize
 params[:reco] = "direct"
@@ -169,4 +172,4 @@
 
 save("fig_bart_julia.png",f)
 save("fig_bart_julia.eps",f)
-save("fig_bart_julia.pdf",f)

This page was generated using Literate.jl.

+save("fig_bart_julia.pdf",f)

This page was generated using Literate.jl.

diff --git a/dev/index.html b/dev/index.html index 9328969..782dcf7 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,2 +1,2 @@ -Home · Subspace_MESE.jl

Subspace_MESE

Documentation for the Subspace_MESE package, which implements the necessary functions to convert and reconstruct an accelerated 3D Multi-Echo Spin-Echo sequence with a subspace reconstruction in order to generate T2 maps.

How to give credit

If you use this package please acknowledge us by citing : https://doi.org/10.1002/mrm.30146

Additionally, if you use the sequence available in the MR sequence folder, please contact us to sign the sequence transfer agreement : aurelien.trotier@rmsb.u-bordeaux.fr

Bruker Acquisition

This package is compatible with the sequence : a_MESE_CS which is available as a binary file in the folder : MR_sequence

The sequence is only available for the version PV6.0.1, PV360:3.5 and 3.6. The protocol used for an acceleration factor of CS=8 is also available.

Reconstruction Pipeline

The reconstruction pipeline includes 4 steps :

  • Conversion of the Bruker rawdataset to a MRIReco compatible format (/src/bruker_sequence.jl)
  • Generation of the subspace (/src/build_basis.jl)
  • Reconstruction of the subspace coefficient and the virtual echo images
  • T2 fitting (/src/fit_T2_MESE.jl)

Reconstruction Pipeline

Those steps are described in their dedicated sections.

Example

Reproduction of figure 8 can be performed at this link

+Home · Subspace_MESE.jl

Subspace_MESE

Documentation for the Subspace_MESE package, which implements the necessary functions to convert and reconstruct an accelerated 3D Multi-Echo Spin-Echo sequence with a subspace reconstruction in order to generate T2 maps.

How to give credit

If you use this package please acknowledge us by citing : https://doi.org/10.1002/mrm.30146

Additionally, if you use the sequence available in the MR sequence folder, please contact us to sign the sequence transfer agreement : aurelien.trotier@rmsb.u-bordeaux.fr

Bruker Acquisition

This package is compatible with the sequence : a_MESE_CS which is available as a binary file in the folder : MR_sequence

The sequence is only available for the version PV6.0.1, PV360:3.5 and 3.6. The protocol used for an acceleration factor of CS=8 is also available.

Reconstruction Pipeline

The reconstruction pipeline includes 4 steps :

  • Conversion of the Bruker rawdataset to a MRIReco compatible format (/src/bruker_sequence.jl)
  • Generation of the subspace (/src/build_basis.jl)
  • Reconstruction of the subspace coefficient and the virtual echo images
  • T2 fitting (/src/fit_T2_MESE.jl)

Reconstruction Pipeline

Those steps are described in their dedicated sections.

Example

Reproduction of figure 8 can be performed at this link

diff --git a/dev/installation/index.html b/dev/installation/index.html index 6657532..614e513 100644 --- a/dev/installation/index.html +++ b/dev/installation/index.html @@ -2,4 +2,4 @@ Installation · Subspace_MESE.jl

Unregistered package Installation

You can install the package in any project with the following command :

  • launch julia with the command julia
  • enter the Julia package manager by typing ] in the REPL. (the REPL should turn in blue)
  • if you want to activate an environment, type : activate . (otherwise the package will be installed in the global environment)
  • In order to add our unregistered package, type add https://github.com/CRMSB/PAPER_subspace_MESE
  • if you want to use the package : using Subspace_MESE

Reproducing figure 8

In order to reproduce figure 8, you need to :

  • compile the BART toolbox : https://mrirecon.github.io/bart/ (you can skip this step if you don't want to plot the BART reconstruction). After compilation/installation you can check the library path with which bart
  • download the dataset : https://zenodo.org/records/10610639 and extract the zip file.
  • download the current repository : git clone https://github.com/CRMSB/PAPER_subspace_MESE
  • Open a terminal and move to the docs folder in this repository
  • edit the script in docs/lit/example/subspace_julia_epg.jl and put the correct path in the variable
    • line 27 : path_raw should point to the bruker folder 10
    • line 30 : path_bart should point to the compiled bart library
  • launch julia in the docs folder with this command in the terminal: julia --project -t auto
  • run the literate example :
    using Pkg
     Pkg.add(url="https://github.com/CRMSB/PAPER_subspace_MESE")
     Pkg.instantiate()
    -include("lit/examples/subspace_julia_epg.jl")

The figure will be saved as fig_bart_julia.png in the docs folder.

+include("lit/examples/subspace_julia_epg.jl")

The figure will be saved as fig_bart_julia.png in the docs folder.

diff --git a/dev/reconstruction_subspace/index.html b/dev/reconstruction_subspace/index.html index d46c012..73c1e99 100644 --- a/dev/reconstruction_subspace/index.html +++ b/dev/reconstruction_subspace/index.html @@ -32,4 +32,4 @@ params[:λ] = 0.01 params[:basis]=basis -im_sub_bart,im_TE_bart = subspace_bart_reconstruction(acq,params,"/home/CODE/bart/bart")

If you need more control over the reconstruction parameters for BART, take a look at the function (only 20 lines)

Note

The regularization parameters between MRIReco.jl and BART are different and need to be adjusted manually. This can be explained by some low-level differences in the FISTA algorithm / Wavelet transform and also due to scaling of the data prior to the algorithm.

+im_sub_bart,im_TE_bart = subspace_bart_reconstruction(acq,params,"/home/CODE/bart/bart")

If you need more control over the reconstruction parameters for BART, take a look at the function (only 20 lines)

Note

The regularization parameters between MRIReco.jl and BART are different and need to be adjusted manually. This can be explained by some low-level differences in the FISTA algorithm / Wavelet transform and also due to scaling of the data prior to the algorithm.

diff --git a/dev/search_index.js b/dev/search_index.js index aec6efc..489f4ab 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"EditURL = \"../../../lit/examples/subspace_julia_epg.jl\"","category":"page"},{"location":"generated/examples/subspace_julia_epg/#03-subspaceReconstruction","page":"Generate figure 8","title":"Generate figure 8","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/#Description","page":"Generate figure 8","title":"Description","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"This example describes how to perform a subspace reconstruction for T_2 mapping. This script is also used to generate the last figure of the article.","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"(Image: Reconstruction Pipeline)","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Reproducibility-setup","page":"Generate figure 8","title":"Reproducibility setup","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"In order to reproduce figure 8, you need to :","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"compile the BART toolbox : https://mrirecon.github.io/bart/ (you can skip this step if you don't want to plot the BART reconstruction). After compilation/installation you can check the library path with which bart\ndownload the dataset : https://zenodo.org/records/10610639 and extract the zip file.\ndownload the current repository : git clone https://github.com/CRMSB/PAPER_subspace_MESE\nOpen a terminal and move to the docs folder in this repository\nedit the script in docs/lit/example/subspace_julia_epg.jl and put the correct path in the variable\nline 46 : path_raw should point to the bruker folder 10\nline 49 : path_bart should point to the compiled bart library\nlaunch julia in the docs folder with this command in the terminal: julia --project -t auto\nrun the literate example :\nusing Pkg\nPkg.add(url=\"https://github.com/CRMSB/PAPER_subspace_MESE\")\nPkg.instantiate()\ninclude(\"lit/examples/subspace_julia_epg.jl\")","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"The figure will be saved as fig_bart_julia.png in the docs folder.","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Load-package","page":"Generate figure 8","title":"Load package","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"using Subspace_MESE\nusing Subspace_MESE.MRIFiles\nusing Subspace_MESE.MRIReco\nusing Subspace_MESE.MRICoilSensitivities\nusing Subspace_MESE.LinearAlgebra\nusing Subspace_MESE.FFTW\nusing CairoMakie","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Define-paths","page":"Generate figure 8","title":"Define paths","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"#to the raw dataset :\n\npath_raw = \"/workspace_QMRI/PROJECTS_DATA/2021_RECH_mcT2_Bruker/PROJ_JULIA_MSME_CS/data/exp_raw/mouse_patho/20230317_085834_AT_MSME_CS_44_1_1/10\"\n\n#and to the bart library :\npath_bart = \"/home/CODE/bart/bart\"\n\nslice_to_show = 55","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Load-and-convert-the-bruker-dataset-into-an-AcquisitionData-object","page":"Generate figure 8","title":"Load and convert the bruker dataset into an AcquisitionData object","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"b = BrukerFile(path_raw)\n\nraw = RawAcquisitionData_MESE(b)\nacq = AcquisitionData(raw,OffsetBruker = true);\nnothing #hide","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Estimate-the-coil-sensitivity-map-with-espirit","page":"Generate figure 8","title":"Estimate the coil sensitivity map with espirit","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"coilsens = espirit(acq,eigThresh_2=0.0);\nnothing #hide","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Direct-reconstruction-of-undersampled-acquisition","page":"Generate figure 8","title":"Direct reconstruction of undersampled acquisition","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"params = Dict{Symbol,Any}()\nparams[:reconSize] = acq.encodingSize\nparams[:reco] = \"direct\"\n\nim_u = reconstruction(acq, params);\nim_u_sos = mergeChannels(im_u)\n\nheatmap(im_u_sos[:,:,55,15,1,1],colormap=:grays)","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Subspace-generation-with-the-EPG-simulation","page":"Generate figure 8","title":"Subspace generation with the EPG simulation","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"B1_vec = 0.8:0.01:1.0\nT2_vec = 1.0:1.0:2000.0\nT1_vec = 1000.0\nTE = 7.0\nTR = 1000.0\ndummy=3\nETL = 50\nNUM_BASIS = 6\nbasis_epg,_= MESE_basis_EPG(NUM_BASIS,TE,ETL,T2_vec,B1_vec,T1_vec;TR=TR,dummy=dummy)\nlines(abs.(basis_epg[:,2]))","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Subspace-reconstruction-with-EPG-dictionary","page":"Generate figure 8","title":"Subspace reconstruction with EPG dictionary","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"params = Dict{Symbol,Any}()\nparams[:reconSize] = acq.encodingSize\nparams[:reco] = \"multiCoilMultiEchoSubspace\"\n\nparams[:regularization] = \"L1\"\nparams[:sparseTrafo] = \"Wavelet\" #sparse trafo\nparams[:λ] = Float32(0.03)\nparams[:solver] = \"fista\"\nparams[:iterations] = 60\n#params[:iterationsInner] = 5\nparams[:senseMaps] = coilsens\nparams[:normalizeReg] = true\nparams[:basis] = basis_epg\n\nα_epg = reconstruction(acq, params)\nim_TE_julia = abs.(applySubspace(α_epg, params[:basis]));\nnothing #hide","category":"page"},{"location":"generated/examples/subspace_julia_epg/#BART-reconstruction","page":"Generate figure 8","title":"BART reconstruction","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"In order to use BartIO, we need to send the path to the bart library. You can check that it works with the following code","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"BartIO.set_bart_path(\"path_bart\")\nbart()","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"if isfile(path_bart)\n using Subspace_MESE.BartIO\n\n params[:λ] = Float32(0.0025)\n im_sub_bart,im_TE_bart = subspace_bart_reconstruction(acq,params,path_bart)\nend;\nnothing #hide","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Fitting-of-the-data-to-obtain-T-maps","page":"Generate figure 8","title":"Fitting of the data to obtain T₂ maps","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"TE_vec = Float32.(LinRange(TE,TE*ETL,ETL))\n\nsl = Tuple[]\npush!(sl,(:,:,slice_to_show))\npush!(sl,(:,65,:))\npush!(sl,(65,:,:))\n\nfit_und = Any[]\nfit_julia = Any[]\nfit_bart = Any[]\nfor i in eachindex(sl)\n push!(fit_und,Subspace_MESE.T2Fit_exp_noise(abs.(im_u_sos[sl[i]...,:,1,1]),TE_vec;removePoint=true,L=4))\n push!(fit_julia,Subspace_MESE.T2Fit_exp_noise(abs.(im_TE_julia[sl[i]...,:,1,1]),TE_vec;removePoint=true,L=4))\n if isfile(path_bart)\n push!(fit_bart,Subspace_MESE.T2Fit_exp_noise(abs.(im_TE_bart[sl[i]...,1,1,:]),TE_vec;removePoint=true,L=4))\n end;\nend","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Visualization-of-the-article-figure-8","page":"Generate figure 8","title":"Visualization of the article figure 8","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"using CairoMakie.Makie.MakieCore\nbegin\ntitlesize=20\nylabelsize=20\naspect = DataAspect()\n\nf=Figure(size=(1200,1600))\n#plot echo 1\ncolorrange=MakieCore.Automatic()\ncolormap=:grays\n\nax = Axis(f[1,1];title=\"FFT\\n \",ylabel = \"Echo n°1\\nTE = 7 ms\",titlesize,ylabelsize)\nheatmap!(ax,circshift(im_u_sos[:,:,slice_to_show,1,1,1],(0,-10));colorrange,colormap)\nhidedecorations!(ax,label=false)\nax = Axis(f[1,2];title=\"MRIReco\\nW=0.03\",titlesize)\nheatmap!(ax,circshift(im_TE_julia[:,:,slice_to_show,1,1,1],(0,-10));colorrange,colormap)\nhidedecorations!(ax)\n\nif(isfile(path_bart))\n ax = Axis(f[1,3];title=\"BART\\nW=0.0025\",titlesize)\n heatmap!(ax,circshift(abs.(im_TE_bart[:,:,slice_to_show,1,1,1]),(0,-10));colorrange,colormap)\n hidedecorations!(ax)\nend\n\n#plot echo 10\n\nax = Axis(f[2,1];ylabel = \"Echo n°10\\nTE = 70 ms\",titlesize,ylabelsize)\nheatmap!(ax,circshift(im_u_sos[:,:,slice_to_show,10,1,1],(0,-10));colorrange,colormap)\nhidedecorations!(ax,label=false)\nax = Axis(f[2,2];titlesize)\nheatmap!(ax,circshift(im_TE_julia[:,:,slice_to_show,10,1,1],(0,-10));colorrange,colormap)\nhidedecorations!(ax)\n\nif(isfile(path_bart))\n ax = Axis(f[2,3];titlesize)\n heatmap!(ax,circshift(abs.(im_TE_bart[:,:,slice_to_show,1,1,10]),(0,-10));colorrange,colormap)\n hidedecorations!(ax)\nend\n\n#plot T2 map\ncolorrange=(0,150)\ncolormap=:magma\n\nax = Axis(f[3,1];ylabel = \"T₂ map: coronal\",titlesize,ylabelsize)\nheatmap!(ax,circshift(fit_und[1][:,:,2],(0,-10));colorrange,colormap)\nhidedecorations!(ax,label=false)\nax = Axis(f[3,2])\nh=heatmap!(ax,circshift(fit_julia[1][:,:,2],(0,-10));colorrange,colormap)\nhidedecorations!(ax)\nif(isfile(path_bart))\n ax = Axis(f[3,3])\n heatmap!(ax,circshift(fit_bart[1][:,:,2],(0,-10));colorrange,colormap)\n hidedecorations!(ax)\nend\nColorbar(f[3,4],h,label = \"T₂ [ms]\",labelrotation=-pi/2,labelsize=20)\n#rowgap!(f.layout,3,10)\n\n#plot T2 sag\nsl_c = (0,20)\nax = Axis(f[4,1];ylabel = \"T₂ map: sagittal\",titlesize,ylabelsize,aspect=128/96)\nheatmap!(ax,circshift(reverse(fit_und[2][:,:,2],dims=2),sl_c);colorrange,colormap)\nhidedecorations!(ax,label=false)\nax = Axis(f[4,2],aspect=128/96)\nh=heatmap!(ax,circshift(reverse(fit_julia[2][:,:,2],dims=2),sl_c);colorrange,colormap)\nhidedecorations!(ax)\nif(isfile(path_bart))\n ax = Axis(f[4,3],aspect=128/96)\n heatmap!(ax,circshift(reverse(fit_bart[2][:,:,2],dims=2),sl_c);colorrange,colormap)\n hidedecorations!(ax)\nend\nColorbar(f[4,4],h,label = \"T₂ [ms]\",labelrotation=-pi/2,labelsize=20,height=Relative(0.85))\nrowgap!(f.layout,3,-10)\n\n#plot T2 axial\nsl_c = (-10,20)\nax = Axis(f[5,1];ylabel = \"T₂ map : axial\",titlesize,ylabelsize,aspect=128/96)\nheatmap!(ax,circshift(reverse(fit_und[3][:,:,2],dims=2),sl_c);colorrange,colormap)\nhidedecorations!(ax,label=false)\nax = Axis(f[5,2],aspect=128/96)\nh=heatmap!(ax,circshift(reverse(fit_julia[3][:,:,2],dims=2),sl_c);colorrange,colormap)\nhidedecorations!(ax)\nif(isfile(path_bart))\n ax = Axis(f[5,3],aspect=128/96)\n heatmap!(ax,circshift(reverse(fit_bart[3][:,:,2],dims=2),sl_c);colorrange,colormap)\n hidedecorations!(ax)\nend\nColorbar(f[5,4],h,label = \"T₂ [ms]\",labelrotation=-pi/2,labelsize=20,height=Relative(0.85))\nrowgap!(f.layout,4,-35)\n\nf\nend\n\nsave(\"fig_bart_julia.png\",f)\nsave(\"fig_bart_julia.eps\",f)\nsave(\"fig_bart_julia.pdf\",f)","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"This page was generated using Literate.jl.","category":"page"},{"location":"fit_T2/#Fitting-the-data","page":"T₂ mapping","title":"Fitting the data","text":"","category":"section"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"The reconstruction and the fitting parts are totally independent.","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"The fitting functions expect a multidimensionnal-array with the echoes along the last dimension. The images should not be in complex, remember to use abs.(img).","category":"page"},{"location":"fit_T2/#Exponential-T_2-fitting-noise","page":"T₂ mapping","title":"Exponential T_2 fitting + noise","text":"","category":"section"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"In the publication we used an analytical model to fit the exponential decay of the echoes :","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"S(t) = sqrtleft(M_0 exp(-fractT_2)right)^2 + 2 L sigma_g^2","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"where L is the number of coil and sigma_g corresponds to the gaussian noise level on the image.","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"You can perform this fit with the following function :","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"T2Fit_exp_noise","category":"page"},{"location":"fit_T2/#Subspace_MESE.T2Fit_exp_noise","page":"T₂ mapping","title":"Subspace_MESE.T2Fit_exp_noise","text":" T2Fit_exp_noise(ima::Array{T,N}, t::AbstractVector{T}; removePoint::Bool=true, L::Int=1, mask = nothing) where {T<:Real,N}\n\nFit the relaxation parameters T2 with the equation : S(t) = sqrt(M_0 exp(-fractT2))^2 + 2 L sigma_g^2 where L est le nombre de canaux, et sigma_g le bruit gaussien sur les image\n\nArguments\n\nima::Array{T,N}: multi-dimensionnal images. Last dimension stores the temporal dimension\nt::AbstractVector{<:Real}: times vector in ms\np0=nothing: starting values for fit, if empty p0=[maximum(ima),30,maximum(ima)*0.1]\n\nKeywords\n\nremovePoint::Bool=true: remove the first point before fitting\nL::Int=1: Number of coil elements\nmask::\n\nReturns\n\nfit_params : parameter maps last dimension stores the following maps (M₀ , T₂ , σ)\n\nBibliography\n\nCárdenas-Blanco A, Tejos C, Irarrazaval P, Cameron I. Noise in magnitude magnetic\n\nresonance images. Concepts Magn Reson Part A [Internet]. 2008 Nov;32A(6):409?16. Available from: http://doi.wiley.com/10.1002/cmr.a.20124\n\nFeng Y, He T, Gatehouse PD, Li X, Harith Alam M, Pennell DJ, et al. Improved MRI R 2 *\n\nrelaxometry of iron-loaded liver with noise correction. Magn Reson Med [Internet]. 2013 Dec;70(6):1765?74. Available from: http://doi.wiley.com/10.1002/mrm.24607\n\n\n\n\n\n","category":"function"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"The keyword removePoint can be used to delete the first point in the TE vector as well as the first temporal volume in order to reduce the sensitivity of the fit to the stimulated echo.","category":"page"},{"location":"fit_T2/#EPG-T_2-fitting-noise-(WIP)","page":"T₂ mapping","title":"EPG T_2 fitting + noise (WIP)","text":"","category":"section"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"Another possibility is to fit the equation with an EPG model that, in addition to M_0/T_2/sigma, also fits the B_1 field.","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"With the current implementation, the fit is not robust enough and also takes too long to use on a 3D volume.","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"T2Fit_epg_noise","category":"page"},{"location":"api/","page":"API","title":"API","text":"","category":"page"},{"location":"api/","page":"API","title":"API","text":"Modules = [Subspace_MESE]","category":"page"},{"location":"api/#Subspace_MESE.MESE_EPG-Union{Tuple{Ty}, Tuple{Ty, Ty, Ty, Ty, Int64, Ty, Int64}} where Ty<:AbstractFloat","page":"API","title":"Subspace_MESE.MESE_EPG","text":"MESE_EPG(T2::Ty,T1::Ty,TE::Ty,TR::Ty,ETL::Int,delta::Ty,dummy::Int) where Ty <: AbstractFloat\n\nGenerate the signal evolution of a Multi-Echo Spin-Echo sequence with an Extended Phase Graph model.\n\nInput :\n\n- `T2` : Transverse relaxation\n- `T1` : Longitudinal relaxation\n- `TE` : Echo Time\n- `TR` : Repetition time\n- `ETL` : Echo Train Length\n\nOutput :\n\n- Amplitude of each echoes\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.MESE_basis_EPG","page":"API","title":"Subspace_MESE.MESE_basis_EPG","text":"MESE_basis_EPG(NUM_BASIS::Int,TE,ETL::Int,T2_vec::Union{AbstractVector,AbstractFloat},B1_vec::Union{AbstractVector,AbstractFloat} = 1.0,T1_vec::Union{AbstractVector,AbstractFloat}=1000.0;TR = 1000.0,dummy::Int = 3)\n\nGenerate a temporal basis for a Multi-Echo Spin-Echo sequence with an Extended Phase Graph model for various value of T2/B1/T1\n\nstored as a vector in T2_vec/B1_vec/T1_vec.\n\nInput :\n\n- `NUM_BASIS::Int : Number of temporal basis to extract\n- `TE::AbstractFloat` : Cartesian acquisition with a fully-sampled center.\n- `ETL::Int` : Echo Train Length\n- `T2_vec::Union{AbstractVector,AbstractFloat}` : Vector of T₂ values used to generate the signal dictionnary \n- `B1_vec::Union{AbstractVector,AbstractFloat}` : Vector of B₁ values used to generate the signal dictionnary \n- `T1_vec::Union{AbstractVector,AbstractFloat}` : Vector of T₁ values used to generate the signal dictionnary\n\nKeyword :\n\n- `TR` : Repetition time\n- `dummy` : Number of dummy scan before extracting the signal value\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `epg_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nB1_vec = 0.8:0.01:1.0\nT2_vec = 1.0:1.0:2000.0\nT1_vec = 1000.0 #can also be a float\nTE = 7.0\nTR = 1000.0\ndummy=3\nETL = 50\nNUM_BASIS = 6\n\nbasis_epg, epg_dict =MESE_basis_EPG(NUM_BASIS,TE,ETL,T2_vec,B1_vec,T1_vec;TR=TR,dummy=dummy)\n\n\n\n\n\n","category":"function"},{"location":"api/#Subspace_MESE.MESE_basis_exp-Tuple{Int64, AbstractFloat, Int64, AbstractVector}","page":"API","title":"Subspace_MESE.MESE_basis_exp","text":" MESE_basis_exp(NUM_BASIS::Int,TE::AbstractFloat,ETL::Int, T2_vec::AbstractVector;removeFirstPoint::Bool=false)\n\nGenerate a temporal basis for a Multi-Echo Spin-Echo sequence with an exponential model.for various value of T2 stored as a vector in T2_vec. The first point of the echo train can be removed from the dictionnary with the keyword removeFirstPoint to minimize the effect of stimulated echoes. \n\nInput :\n\n- `NUM_BASIS::Int : Number of temporal basis to extract\n- `TE::AbstractFloat` : Cartesian acquisition with a fully-sampled center.\n- `ETL::Int` : Echo Train Length\n- `T2_vec::AbstractVector` : Vector of T₂ values used to generate the signal dictionnary\n\nKeyword :\n\n- `removeFirstPoint::Bool=False` : Remove the first point of the dictionnary before the svd\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `exp_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nT2_vec = 1.0:1.0:2000.0\nTE = 7.0\nETL = 50\nNUM_BASIS = 6\n\nbasis_exp,exp_dict = MESE_basis_exp(NUM_BASIS,TE,ETL,T2_vec)\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.RawAcquisitionData_MESE-Tuple{MRIFiles.BrukerFile}","page":"API","title":"Subspace_MESE.RawAcquisitionData_MESE","text":"RawAcquisitionData_MESE(b::BrukerFile)\n\nConvert a Bruker dataset acquired with the aMESECS sequence into a RawAcquisitionData object compatible with the MRIReco functions.\n\nInput : - b::BrukerFile\n\nOutput : - raw::RawAcquisitionData\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.RawAcquisitionData_MESE_PV360-Tuple{MRIFiles.BrukerFile}","page":"API","title":"Subspace_MESE.RawAcquisitionData_MESE_PV360","text":"RawAcquisitionData_MESE_PV360(b::BrukerFile)\n\nConvert a Bruker dataset acquired with the aMESECS_360 sequence into a RawAcquisitionData object compatible with the MRIReco functions.\n\nInput : - b::BrukerFile\n\nOutput : - raw::RawAcquisitionData\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.RawAcquisitionData_MESE_PV6-Tuple{MRIFiles.BrukerFile}","page":"API","title":"Subspace_MESE.RawAcquisitionData_MESE_PV6","text":"RawAcquisitionData_MESE_PV6(b::BrukerFile)\n\nConvert a Bruker dataset acquired with the aMESECS sequence into a RawAcquisitionData object compatible with the MRIReco functions.\n\nInput : - b::BrukerFile\n\nOutput : - raw::RawAcquisitionData\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.T2Fit_epg_noise-Union{Tuple{N}, Tuple{T}, Tuple{Array{T, N}, AbstractVector{T}}, Tuple{Array{T, N}, AbstractVector{T}, Any}, Tuple{Array{T, N}, AbstractVector{T}, Any, Any}} where {T<:Real, N}","page":"API","title":"Subspace_MESE.T2Fit_epg_noise","text":"T2Fit_epg_noise(ima::Array{T,N}, t::AbstractVector{T},T1=1000.0,TE=7.0; EPGthresh = 1e-5,p0=nothing,mask = nothing) where {T<:Real,N}\n\nWIP\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.T2Fit_exp_noise-Union{Tuple{N}, Tuple{T}, Tuple{Array{T, N}, AbstractVector{T}}} where {T<:Real, N}","page":"API","title":"Subspace_MESE.T2Fit_exp_noise","text":" T2Fit_exp_noise(ima::Array{T,N}, t::AbstractVector{T}; removePoint::Bool=true, L::Int=1, mask = nothing) where {T<:Real,N}\n\nFit the relaxation parameters T2 with the equation : S(t) = sqrt(M_0 exp(-fractT2))^2 + 2 L sigma_g^2 where L est le nombre de canaux, et sigma_g le bruit gaussien sur les image\n\nArguments\n\nima::Array{T,N}: multi-dimensionnal images. Last dimension stores the temporal dimension\nt::AbstractVector{<:Real}: times vector in ms\np0=nothing: starting values for fit, if empty p0=[maximum(ima),30,maximum(ima)*0.1]\n\nKeywords\n\nremovePoint::Bool=true: remove the first point before fitting\nL::Int=1: Number of coil elements\nmask::\n\nReturns\n\nfit_params : parameter maps last dimension stores the following maps (M₀ , T₂ , σ)\n\nBibliography\n\nCárdenas-Blanco A, Tejos C, Irarrazaval P, Cameron I. Noise in magnitude magnetic\n\nresonance images. Concepts Magn Reson Part A [Internet]. 2008 Nov;32A(6):409?16. Available from: http://doi.wiley.com/10.1002/cmr.a.20124\n\nFeng Y, He T, Gatehouse PD, Li X, Harith Alam M, Pennell DJ, et al. Improved MRI R 2 *\n\nrelaxometry of iron-loaded liver with noise correction. Magn Reson Med [Internet]. 2013 Dec;70(6):1765?74. Available from: http://doi.wiley.com/10.1002/mrm.24607\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.basis_calibration-Union{Tuple{D}, Tuple{T}, Tuple{Int64, MRIBase.AcquisitionData{T, D}, NTuple{D, Int64}}} where {T, D}","page":"API","title":"Subspace_MESE.basis_calibration","text":"basis_calibration(NUM_BASIS::Int,acq::AcquisitionData{T,D},crop_size::NTuple{D,Int}) where {T,D}\n\nk_bart = kDataCart(acq); \n\nExtract a temporal basis from a low-resolution images reconstructed using a fully sampled area at the center of the k-space with a size crop_size. \n\nInput :\n\n- `NUM_BASIS::Int : Number of temporal basis to extract\n- `acq::AcquisitionData` : Cartesian acquisition with a fully-sampled center.\n- `crop_size::NTuple{D,Int})` : size of the central part of k-space used\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `calib_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nb = BrukerFile(\"path/to/dataset\")\n\nraw = RawAcquisitionData_MESE(b)\nacq = AcquisitionData(raw,OffsetBruker = true);\n\nbasis, calib_dict = MESE_basis_calibration(acq,(15,15,15),6)\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.subspace_bart_reconstruction-Tuple{MRIBase.AcquisitionData, Dict{Symbol, Any}, AbstractString}","page":"API","title":"Subspace_MESE.subspace_bart_reconstruction","text":"subspace_bart_reconstruction(acq::AcquisitionData,params::Dict{Symbol,Any},bart_path::AbstractString)\n\nReconstruction of the accelerated MESE sequence with BART.\n\nInput :\n\n- `acq::AcquisitionData` : Cartesian acquisition with a fully-sampled center.\n- `params::Dict{Symbol,Any}` : size of the central part of k-space used\n- `bart_path::AbstractString` : path to the BART executable library\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `calib_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nb = BrukerFile(\"path/to/dataset\")\n\nraw = RawAcquisitionData_MESE(b)\nacq = AcquisitionData(raw,OffsetBruker = true);\n\nbasis, calib_dict = MESE_basis_calibration(acq,(15,15,15),6)\n\n\n\n\n\n","category":"method"},{"location":"building_basis/#Generate-Subspaces","page":"Subspace generation","title":"Generate Subspaces","text":"","category":"section"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"This package implements 3 different subspaces :","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Exponential\nExtended Phase Graph (EPG)\nCalibration","category":"page"},{"location":"building_basis/#How-to-build-a-subspace","page":"Subspace generation","title":"How to build a subspace","text":"","category":"section"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"The 3 methods are based on the same concept :","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Generate a dictionary with the signal evolution at each echo time signal_dict","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Apply a Singular Value Decomposition on it","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"svd_obj = svd(signal_dict)","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"and then crop to the desired subspace dimension","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"basis = ComplexF32.(svd_obj.V)[:, 1:NUM_BASIS]","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"This concept can be applied to create your own subspace, for example directly from echo images.","category":"page"},{"location":"building_basis/#Difference-between-the-3-methods","page":"Subspace generation","title":"Difference between the 3 methods","text":"","category":"section"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Exponential and EPG subspace generate a dictionary with the signal evolution of the Multi-Echo Spin-Echo sequence for various T_2 (or B_1 for the EPG case).","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"The calibration subspace reconstructs low-resolution images at each Echo Time with the fully sampled area of the k-space.","category":"page"},{"location":"building_basis/#Exponential-subspace","page":"Subspace generation","title":"Exponential subspace","text":"","category":"section"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"MESE_basis_exp","category":"page"},{"location":"building_basis/#Subspace_MESE.MESE_basis_exp","page":"Subspace generation","title":"Subspace_MESE.MESE_basis_exp","text":" MESE_basis_exp(NUM_BASIS::Int,TE::AbstractFloat,ETL::Int, T2_vec::AbstractVector;removeFirstPoint::Bool=false)\n\nGenerate a temporal basis for a Multi-Echo Spin-Echo sequence with an exponential model.for various value of T2 stored as a vector in T2_vec. The first point of the echo train can be removed from the dictionnary with the keyword removeFirstPoint to minimize the effect of stimulated echoes. \n\nInput :\n\n- `NUM_BASIS::Int : Number of temporal basis to extract\n- `TE::AbstractFloat` : Cartesian acquisition with a fully-sampled center.\n- `ETL::Int` : Echo Train Length\n- `T2_vec::AbstractVector` : Vector of T₂ values used to generate the signal dictionnary\n\nKeyword :\n\n- `removeFirstPoint::Bool=False` : Remove the first point of the dictionnary before the svd\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `exp_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nT2_vec = 1.0:1.0:2000.0\nTE = 7.0\nETL = 50\nNUM_BASIS = 6\n\nbasis_exp,exp_dict = MESE_basis_exp(NUM_BASIS,TE,ETL,T2_vec)\n\n\n\n\n\n","category":"function"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"In the publication, the subspace is extracted from a dictionary generated with a range of T_2 from 1 ms to 2000 ms with a step of 1 ms.","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Other approachs can be used :","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"a logarithmic repartition of T_2 \nextracting from a fully acquisition the distribution of T_2 and then generate from that distribution the dictionary (Tamir et al, MRM,2017)","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Let's take a look at the first 6 subspace vectors from a linear repartition :","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"using Subspace_MESE\n\nT2_vec = 1.0:1.0:2000.0\nTE = 7.0\nETL = 50\nNUM_BASIS = 6\n\nbasis_exp,_=MESE_basis_exp(NUM_BASIS,TE,ETL,T2_vec)\n\nusing CairoMakie\ncolor = Makie.wong_colors()\nf = Figure()\nax=Axis(f[1,1])\nfor b in 1:6\n lines!(ax,abs.(basis_exp[:,b]),color=color[b],label = \"Basis n°$b\")\nend\nhidedecorations!(ax)\naxislegend(ax)\nf","category":"page"},{"location":"building_basis/#EPG-subspace","page":"Subspace generation","title":"EPG subspace","text":"","category":"section"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"MESE_basis_EPG","category":"page"},{"location":"building_basis/#Subspace_MESE.MESE_basis_EPG","page":"Subspace generation","title":"Subspace_MESE.MESE_basis_EPG","text":"MESE_basis_EPG(NUM_BASIS::Int,TE,ETL::Int,T2_vec::Union{AbstractVector,AbstractFloat},B1_vec::Union{AbstractVector,AbstractFloat} = 1.0,T1_vec::Union{AbstractVector,AbstractFloat}=1000.0;TR = 1000.0,dummy::Int = 3)\n\nGenerate a temporal basis for a Multi-Echo Spin-Echo sequence with an Extended Phase Graph model for various value of T2/B1/T1\n\nstored as a vector in T2_vec/B1_vec/T1_vec.\n\nInput :\n\n- `NUM_BASIS::Int : Number of temporal basis to extract\n- `TE::AbstractFloat` : Cartesian acquisition with a fully-sampled center.\n- `ETL::Int` : Echo Train Length\n- `T2_vec::Union{AbstractVector,AbstractFloat}` : Vector of T₂ values used to generate the signal dictionnary \n- `B1_vec::Union{AbstractVector,AbstractFloat}` : Vector of B₁ values used to generate the signal dictionnary \n- `T1_vec::Union{AbstractVector,AbstractFloat}` : Vector of T₁ values used to generate the signal dictionnary\n\nKeyword :\n\n- `TR` : Repetition time\n- `dummy` : Number of dummy scan before extracting the signal value\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `epg_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nB1_vec = 0.8:0.01:1.0\nT2_vec = 1.0:1.0:2000.0\nT1_vec = 1000.0 #can also be a float\nTE = 7.0\nTR = 1000.0\ndummy=3\nETL = 50\nNUM_BASIS = 6\n\nbasis_epg, epg_dict =MESE_basis_EPG(NUM_BASIS,TE,ETL,T2_vec,B1_vec,T1_vec;TR=TR,dummy=dummy)\n\n\n\n\n\n","category":"function"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"In order to generate the EPG subspace, more parameters need to be defined. Specifically, the range of B_1 to be expected in the acquisition might be larger for surfacic transmit coil than for volumic coils that have a homogeneous B_1^+ field.","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Of note, B1vec, T2vec, T1vec can also be passed as float values rather than vectors. In the publication, the T1vec was fixed to 1000 ms.","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"using Subspace_MESE\nB1_vec = 0.8:0.01:1.0\nT2_vec = 1.0:1.0:2000.0\nT1_vec = 1000.0 #can also be a vector of float\nTE = 7.0\nTR = 1000.0\ndummy=3\nETL = 50\nNUM_BASIS = 6\n\nbasis_epg,_=MESE_basis_EPG(NUM_BASIS,TE,ETL,T2_vec,B1_vec,T1_vec;TR=TR,dummy=dummy)\n\nusing CairoMakie\ncolor = Makie.wong_colors()\nf = Figure()\nax=Axis(f[1,1])\nfor b in 1:6\n lines!(ax,abs.(basis_epg[:,b]),color=color[b],label = \"Basis n°$b\")\nend\nhidedecorations!(ax)\naxislegend(ax)\nf","category":"page"},{"location":"building_basis/#Calibration-subspace","page":"Subspace generation","title":"Calibration subspace","text":"","category":"section"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"basis_calibration","category":"page"},{"location":"building_basis/#Subspace_MESE.basis_calibration","page":"Subspace generation","title":"Subspace_MESE.basis_calibration","text":"basis_calibration(NUM_BASIS::Int,acq::AcquisitionData{T,D},crop_size::NTuple{D,Int}) where {T,D}\n\nk_bart = kDataCart(acq); \n\nExtract a temporal basis from a low-resolution images reconstructed using a fully sampled area at the center of the k-space with a size crop_size. \n\nInput :\n\n- `NUM_BASIS::Int : Number of temporal basis to extract\n- `acq::AcquisitionData` : Cartesian acquisition with a fully-sampled center.\n- `crop_size::NTuple{D,Int})` : size of the central part of k-space used\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `calib_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nb = BrukerFile(\"path/to/dataset\")\n\nraw = RawAcquisitionData_MESE(b)\nacq = AcquisitionData(raw,OffsetBruker = true);\n\nbasis, calib_dict = MESE_basis_calibration(acq,(15,15,15),6)\n\n\n\n\n\n","category":"function"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"The calibration subspace reconstructs low-resolution images from a fully sampled area of the k-space. ","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"You can generate the subspace from the acquired accelerated acquisition with the parameter crop_size equal to the size of the fully sampled area of the k-space.","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"But you can also generate the subspace from a different fully acquisition (for example on a control acquisition)","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"b = BrukerFile(\"path/to/dataset\")\n\nraw = RawAcquisitionData_MESE(b)\nacq = AcquisitionData(raw,OffsetBruker = true);\n\nbasis,_ = MESE_basis_calibration(acq,(15,15,15),6)","category":"page"},{"location":"installation/#Unregistered-package-Installation","page":"Installation","title":"Unregistered package Installation","text":"","category":"section"},{"location":"installation/","page":"Installation","title":"Installation","text":"You can install the package in any project with the following command :","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"launch julia with the command julia\nenter the Julia package manager by typing ] in the REPL. (the REPL should turn in blue)\nif you want to activate an environment, type : activate . (otherwise the package will be installed in the global environment)\nIn order to add our unregistered package, type add https://github.com/CRMSB/PAPER_subspace_MESE\nif you want to use the package : using Subspace_MESE","category":"page"},{"location":"installation/#Reproducing-figure-8","page":"Installation","title":"Reproducing figure 8","text":"","category":"section"},{"location":"installation/","page":"Installation","title":"Installation","text":"In order to reproduce figure 8, you need to :","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"compile the BART toolbox : https://mrirecon.github.io/bart/ (you can skip this step if you don't want to plot the BART reconstruction). After compilation/installation you can check the library path with which bart\ndownload the dataset : https://zenodo.org/records/10610639 and extract the zip file.\ndownload the current repository : git clone https://github.com/CRMSB/PAPER_subspace_MESE\nOpen a terminal and move to the docs folder in this repository\nedit the script in docs/lit/example/subspace_julia_epg.jl and put the correct path in the variable \nline 27 : path_raw should point to the bruker folder 10\nline 30 : path_bart should point to the compiled bart library\nlaunch julia in the docs folder with this command in the terminal: julia --project -t auto\nrun the literate example :\nusing Pkg\nPkg.add(url=\"https://github.com/CRMSB/PAPER_subspace_MESE\")\nPkg.instantiate()\ninclude(\"lit/examples/subspace_julia_epg.jl\")","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"The figure will be saved as fig_bart_julia.png in the docs folder.","category":"page"},{"location":"","page":"Home","title":"Home","text":"CurrentModule = Subspace_MESE","category":"page"},{"location":"#Subspace_MESE","page":"Home","title":"Subspace_MESE","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Documentation for the Subspace_MESE package, which implements the necessary functions to convert and reconstruct an accelerated 3D Multi-Echo Spin-Echo sequence with a subspace reconstruction in order to generate T2 maps.","category":"page"},{"location":"#How-to-give-credit","page":"Home","title":"How to give credit","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"If you use this package please acknowledge us by citing : https://doi.org/10.1002/mrm.30146","category":"page"},{"location":"","page":"Home","title":"Home","text":"Additionally, if you use the sequence available in the MR sequence folder, please contact us to sign the sequence transfer agreement : aurelien.trotier@rmsb.u-bordeaux.fr","category":"page"},{"location":"#Bruker-Acquisition","page":"Home","title":"Bruker Acquisition","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"This package is compatible with the sequence : a_MESE_CS which is available as a binary file in the folder : MR_sequence","category":"page"},{"location":"","page":"Home","title":"Home","text":"The sequence is only available for the version PV6.0.1, PV360:3.5 and 3.6. The protocol used for an acceleration factor of CS=8 is also available.","category":"page"},{"location":"#Reconstruction-Pipeline","page":"Home","title":"Reconstruction Pipeline","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"The reconstruction pipeline includes 4 steps :","category":"page"},{"location":"","page":"Home","title":"Home","text":"Conversion of the Bruker rawdataset to a MRIReco compatible format (/src/bruker_sequence.jl)\nGeneration of the subspace (/src/build_basis.jl)\nReconstruction of the subspace coefficient and the virtual echo images\nT2 fitting (/src/fit_T2_MESE.jl)","category":"page"},{"location":"","page":"Home","title":"Home","text":"(Image: Reconstruction Pipeline)","category":"page"},{"location":"","page":"Home","title":"Home","text":"Those steps are described in their dedicated sections.","category":"page"},{"location":"#Example","page":"Home","title":"Example","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Reproduction of figure 8 can be performed at this link","category":"page"},{"location":"reconstruction_subspace/#Compressed-sensing-reconstruction-with-a-subspace-constrained","page":"Subspace Reconstruction","title":"Compressed sensing reconstruction with a subspace constrained","text":"","category":"section"},{"location":"reconstruction_subspace/#Background","page":"Subspace Reconstruction","title":"Background","text":"","category":"section"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"The main idea is to solve the following problem :","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"min_alpha frac12y - E Phi_K alpha^2_2 + lambdaW(alpha)_1","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"where y is the k-space data, E is the encoding operator regrouping the FFT operator and the coil sensitvity operator. Phi_K is the subspace cropped to the first K temporal dimensions, alpha is the subspace coefficient maps and W corresponds to the Wavelet Operator which is applied on alpha.","category":"page"},{"location":"reconstruction_subspace/#Julia-implementation","page":"Subspace Reconstruction","title":"Julia implementation","text":"","category":"section"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"The subspace reconstruction was implemented as part of MRIReco.jl package. An example in the MRIReco.jl package can be found here.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"The reconstruction works on an AcquisitionData object (previously converted from the Bruker raw dataset). Because it is a combined parallel imaging and compressed sensing approach, we have to estimate the coil sensitivity map.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"using Subspace_MESE\nusing Subspace_MESE.MRIFiles\nusing Subspace_MESE.MRIReco\nusing Subspace_MESE.MRICoilSensitivities\n\nb=BrukerFile(\"path/to/dataset/\")\nraw = RawAcquisitionData_MESE(b)\nacq = AcquisitionData(raw,OffsetBruker = true);\n\ncoilsens = espirit(acq,eigThresh_2=0.0);\nbasis,dico = basis_calibration(6,acq,(15,15,15))","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"From that point, we need to define a Dict structure (here named params) to store and pass the MRIReco reconstruction parameters.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"params = Dict{Symbol,Any}()\nparams[:reconSize] = acq.encodingSize\n\n# Subspace \nparams[:reco] = \"multiCoilMultiEchoSubspace\"\nparams[:senseMaps] = coilsens\nparams[:basis] = basis\n\n# Compressed sensing transform\nparams[:regularization] = \"L1\"\nparams[:sparseTrafo] = \"Wavelet\" #sparse trafo\nparams[:λ] = Float32(0.01)\n\n# Algorithm parameters\nparams[:solver] = \"fista\"\nparams[:iterations] = 30\nparams[:normalizeReg] = true","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"params[:reco] = \"multiCoilMultiEchoSubspace\" means that it is a subspace reconstruction with parallel imaging and needs the fields params[:senseMaps] and params[:basis]","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"The remaining parameters are linked to the algorithm used, here a wavelet transform + L1 regularization with a FISTA algorithm and 30 iterations.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"To perform the reconstruction we can now call the function :","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"alpha = reconstruction(acq, params);","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"The results of the reconstruction is not directly the echo images but the subspace coefficient maps. In order to get the virtual echo images, the subspace needs to be applied on this coefficient maps.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"im_TE = abs.(applySubspace(α, basis))","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"warning: Warning\nThe reconstruction part might evolve due to changes in the MRIReco package and its dependencies, particularly RegularizedLeastSquares.jl","category":"page"},{"location":"reconstruction_subspace/#Comparison-with-BART","page":"Subspace Reconstruction","title":"Comparison with BART","text":"","category":"section"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"All the figures (except some parts of figure 8) from the publication were generated using a reconstruction from BART. For comparison purpose, the reconstruction is also available in this package and detailed below.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"You need to compile the BART toolbox : https://mrirecon.github.io/bart/ and pass as an argument the path to the executable BART library in the subspace_bart_reconstruction function.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"This package uses the wrapper BartIO.jl to send the data back and forth between JULIA and BART.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"using Subspace_MESE.BartIO\n\nparams = Dict{Symbol,Any}()\nparams[:iterations] = 60\nparams[:λ] = 0.01\nparams[:basis]=basis\n\nim_sub_bart,im_TE_bart = subspace_bart_reconstruction(acq,params,\"/home/CODE/bart/bart\")","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"If you need more control over the reconstruction parameters for BART, take a look at the function (only 20 lines)","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"note: Note\nThe regularization parameters between MRIReco.jl and BART are different and need to be adjusted manually. This can be explained by some low-level differences in the FISTA algorithm / Wavelet transform and also due to scaling of the data prior to the algorithm.","category":"page"},{"location":"convert/#Conversion-from-Bruker-dataset-to-MRIReco.jl-object","page":"Convert data","title":"Conversion from Bruker dataset to MRIReco.jl object","text":"","category":"section"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"After acquisition, you can convert the Bruker dataset to a RawAcquisitionData with the specific function RawAcquisitionData_MESE(b::BrukerFile). Conversion is mostly performed with MRIReco/MRIBase and MRIFiles functions. ","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"We need to import them first :","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"using Subspace_MESE\nusing Subspace_MESE.MRIFiles\nusing Subspace_MESE.MRIReco\n\nb=BrukerFile(\"path/to/dataset/20230317_085834_AT_MSME_CS_44_1_1/10\")\nraw = RawAcquisitionData_MESE(b)","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"The RawAcquisitionData object is an implementation of the MRD format. After that point the remaining function are purely in the MRIReco.jl package. ","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"In order to perform the reconstruction, the raw object needs to be converted into an AcquisitionData object with the following command :","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"acq = AcquisitionData(raw,OffsetBruker = true);","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"The keyword OffsetBruker is equal to true in order to correct the Field-Of-View offset along the phase and partition directions (specific to Bruker).","category":"page"},{"location":"convert/#Direct-reconstruction","page":"Convert data","title":"Direct reconstruction","text":"","category":"section"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"From that point the user should take a look at the MRIReco.jl documentation in order to perfom the reconstruction. ","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"A direct reconstruction can be performed with : ","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"params = Dict{Symbol,Any}()\nparams[:reconSize] = acq.encodingSize\nparams[:reco] = \"direct\"\n\nim_u = reconstruction(acq, params);","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"This returns images which can be artifacted in the case of an undersampled acquisitioncan.","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"We can combine the different coil elements with a sum of squares :","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"using Subspace_MESE.MRICoilSensitivities\nim_u_sos = mergeChannels(im_u)","category":"page"}] +[{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"EditURL = \"../../../lit/examples/subspace_julia_epg.jl\"","category":"page"},{"location":"generated/examples/subspace_julia_epg/#03-subspaceReconstruction","page":"Generate figure 8","title":"Generate figure 8","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/#Description","page":"Generate figure 8","title":"Description","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"This example describes how to perform a subspace reconstruction for T_2 mapping. This script is also used to generate the last figure of the article.","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"(Image: Reconstruction Pipeline)","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Reproducibility-setup","page":"Generate figure 8","title":"Reproducibility setup","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"In order to reproduce figure 8, you need to :","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"compile the BART toolbox : https://mrirecon.github.io/bart/ (you can skip this step if you don't want to plot the BART reconstruction). After compilation/installation you can check the library path with which bart\ndownload the dataset : https://zenodo.org/records/10610639 and extract the zip file.\ndownload the current repository : git clone https://github.com/CRMSB/PAPER_subspace_MESE\nOpen a terminal and move to the docs folder in this repository\nedit the script in docs/lit/example/subspace_julia_epg.jl and put the correct path in the variable\nline 46 : path_raw should point to the bruker folder 10\nline 49 : path_bart should point to the compiled bart library\nlaunch julia in the docs folder with this command in the terminal: julia --project -t auto\nrun the literate example :\nusing Pkg\nPkg.add(url=\"https://github.com/CRMSB/PAPER_subspace_MESE\")\nPkg.instantiate()\ninclude(\"lit/examples/subspace_julia_epg.jl\")","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"The figure will be saved as fig_bart_julia.png in the docs folder.","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Load-package","page":"Generate figure 8","title":"Load package","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"using Subspace_MESE\nusing Subspace_MESE.MRIFiles\nusing Subspace_MESE.MRIReco\nusing Subspace_MESE.MRICoilSensitivities\nusing Subspace_MESE.LinearAlgebra\nusing Subspace_MESE.FFTW\nusing CairoMakie","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Define-paths","page":"Generate figure 8","title":"Define paths","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"#to the raw dataset :\n\npath_raw = \"/workspace_QMRI/PROJECTS_DATA/2021_RECH_mcT2_Bruker/PROJ_JULIA_MSME_CS/data/exp_raw/mouse_patho/20230317_085834_AT_MSME_CS_44_1_1/10\"\n\n#and to the bart library :\npath_bart = \"/home/CODE/bart/bart\"\n\nslice_to_show = 55","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Load-and-convert-the-bruker-dataset-into-an-AcquisitionData-object","page":"Generate figure 8","title":"Load and convert the bruker dataset into an AcquisitionData object","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"b = BrukerFile(path_raw)\n\nraw = RawAcquisitionData_MESE(b)\nacq = AcquisitionData(raw,OffsetBruker = true);\nnothing #hide","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Estimate-the-coil-sensitivity-map-with-espirit","page":"Generate figure 8","title":"Estimate the coil sensitivity map with espirit","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"ncalib = parse.(Int,b[\"CenterMaskSize\"])\nncalib > 24 ? ncalib = 24 : nothing\n\ncoilsens = espirit(acq,eigThresh_2 = 0,(6,6,6),ncalib);\nnothing #hide","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Direct-reconstruction-of-undersampled-acquisition","page":"Generate figure 8","title":"Direct reconstruction of undersampled acquisition","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"params = Dict{Symbol,Any}()\nparams[:reconSize] = acq.encodingSize\nparams[:reco] = \"direct\"\n\nim_u = reconstruction(acq, params);\nim_u_sos = mergeChannels(im_u)\n\nheatmap(im_u_sos[:,:,55,15,1,1],colormap=:grays)","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Subspace-generation-with-the-EPG-simulation","page":"Generate figure 8","title":"Subspace generation with the EPG simulation","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"B1_vec = 0.8:0.01:1.0\nT2_vec = 1.0:1.0:2000.0\nT1_vec = 1000.0\nTE = 7.0\nTR = 1000.0\ndummy=3\nETL = 50\nNUM_BASIS = 6\nbasis_epg,_= MESE_basis_EPG(NUM_BASIS,TE,ETL,T2_vec,B1_vec,T1_vec;TR=TR,dummy=dummy)\nlines(abs.(basis_epg[:,2]))","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Subspace-reconstruction-with-EPG-dictionary","page":"Generate figure 8","title":"Subspace reconstruction with EPG dictionary","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"params = Dict{Symbol,Any}()\nparams[:reconSize] = acq.encodingSize\nparams[:reco] = \"multiCoilMultiEchoSubspace\"\n\nparams[:regularization] = \"L1\"\nparams[:sparseTrafo] = \"Wavelet\" #sparse trafo\nparams[:λ] = Float32(0.03)\nparams[:solver] = \"fista\"\nparams[:iterations] = 60\n#params[:iterationsInner] = 5\nparams[:senseMaps] = coilsens\nparams[:normalizeReg] = true\nparams[:basis] = basis_epg\n\nα_epg = reconstruction(acq, params)\nim_TE_julia = abs.(applySubspace(α_epg, params[:basis]));\nnothing #hide","category":"page"},{"location":"generated/examples/subspace_julia_epg/#BART-reconstruction","page":"Generate figure 8","title":"BART reconstruction","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"In order to use BartIO, we need to send the path to the bart library. You can check that it works with the following code","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"BartIO.set_bart_path(\"path_bart\")\nbart()","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"if isfile(path_bart)\n using Subspace_MESE.BartIO\n\n params[:λ] = Float32(0.0025)\n im_sub_bart,im_TE_bart = subspace_bart_reconstruction(acq,params,path_bart)\nend;\nnothing #hide","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Fitting-of-the-data-to-obtain-T-maps","page":"Generate figure 8","title":"Fitting of the data to obtain T₂ maps","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"TE_vec = Float32.(LinRange(TE,TE*ETL,ETL))\n\nsl = Tuple[]\npush!(sl,(:,:,slice_to_show))\npush!(sl,(:,65,:))\npush!(sl,(65,:,:))\n\nfit_und = Any[]\nfit_julia = Any[]\nfit_bart = Any[]\nfor i in eachindex(sl)\n push!(fit_und,Subspace_MESE.T2Fit_exp_noise(abs.(im_u_sos[sl[i]...,:,1,1]),TE_vec;removePoint=true,L=4))\n push!(fit_julia,Subspace_MESE.T2Fit_exp_noise(abs.(im_TE_julia[sl[i]...,:,1,1]),TE_vec;removePoint=true,L=4))\n if isfile(path_bart)\n push!(fit_bart,Subspace_MESE.T2Fit_exp_noise(abs.(im_TE_bart[sl[i]...,1,1,:]),TE_vec;removePoint=true,L=4))\n end;\nend","category":"page"},{"location":"generated/examples/subspace_julia_epg/#Visualization-of-the-article-figure-8","page":"Generate figure 8","title":"Visualization of the article figure 8","text":"","category":"section"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"using CairoMakie.Makie.MakieCore\nbegin\ntitlesize=20\nylabelsize=20\naspect = DataAspect()\n\nf=Figure(size=(1200,1600))\n#plot echo 1\ncolorrange=MakieCore.Automatic()\ncolormap=:grays\n\nax = Axis(f[1,1];title=\"FFT\\n \",ylabel = \"Echo n°1\\nTE = 7 ms\",titlesize,ylabelsize)\nheatmap!(ax,circshift(im_u_sos[:,:,slice_to_show,1,1,1],(0,-10));colorrange,colormap)\nhidedecorations!(ax,label=false)\nax = Axis(f[1,2];title=\"MRIReco\\nW=0.03\",titlesize)\nheatmap!(ax,circshift(im_TE_julia[:,:,slice_to_show,1,1,1],(0,-10));colorrange,colormap)\nhidedecorations!(ax)\n\nif(isfile(path_bart))\n ax = Axis(f[1,3];title=\"BART\\nW=0.0025\",titlesize)\n heatmap!(ax,circshift(abs.(im_TE_bart[:,:,slice_to_show,1,1,1]),(0,-10));colorrange,colormap)\n hidedecorations!(ax)\nend\n\n#plot echo 10\n\nax = Axis(f[2,1];ylabel = \"Echo n°10\\nTE = 70 ms\",titlesize,ylabelsize)\nheatmap!(ax,circshift(im_u_sos[:,:,slice_to_show,10,1,1],(0,-10));colorrange,colormap)\nhidedecorations!(ax,label=false)\nax = Axis(f[2,2];titlesize)\nheatmap!(ax,circshift(im_TE_julia[:,:,slice_to_show,10,1,1],(0,-10));colorrange,colormap)\nhidedecorations!(ax)\n\nif(isfile(path_bart))\n ax = Axis(f[2,3];titlesize)\n heatmap!(ax,circshift(abs.(im_TE_bart[:,:,slice_to_show,1,1,10]),(0,-10));colorrange,colormap)\n hidedecorations!(ax)\nend\n\n#plot T2 map\ncolorrange=(0,150)\ncolormap=:magma\n\nax = Axis(f[3,1];ylabel = \"T₂ map: coronal\",titlesize,ylabelsize)\nheatmap!(ax,circshift(fit_und[1][:,:,2],(0,-10));colorrange,colormap)\nhidedecorations!(ax,label=false)\nax = Axis(f[3,2])\nh=heatmap!(ax,circshift(fit_julia[1][:,:,2],(0,-10));colorrange,colormap)\nhidedecorations!(ax)\nif(isfile(path_bart))\n ax = Axis(f[3,3])\n heatmap!(ax,circshift(fit_bart[1][:,:,2],(0,-10));colorrange,colormap)\n hidedecorations!(ax)\nend\nColorbar(f[3,4],h,label = \"T₂ [ms]\",labelrotation=-pi/2,labelsize=20)\n#rowgap!(f.layout,3,10)\n\n#plot T2 sag\nsl_c = (0,20)\nax = Axis(f[4,1];ylabel = \"T₂ map: sagittal\",titlesize,ylabelsize,aspect=128/96)\nheatmap!(ax,circshift(reverse(fit_und[2][:,:,2],dims=2),sl_c);colorrange,colormap)\nhidedecorations!(ax,label=false)\nax = Axis(f[4,2],aspect=128/96)\nh=heatmap!(ax,circshift(reverse(fit_julia[2][:,:,2],dims=2),sl_c);colorrange,colormap)\nhidedecorations!(ax)\nif(isfile(path_bart))\n ax = Axis(f[4,3],aspect=128/96)\n heatmap!(ax,circshift(reverse(fit_bart[2][:,:,2],dims=2),sl_c);colorrange,colormap)\n hidedecorations!(ax)\nend\nColorbar(f[4,4],h,label = \"T₂ [ms]\",labelrotation=-pi/2,labelsize=20,height=Relative(0.85))\nrowgap!(f.layout,3,-10)\n\n#plot T2 axial\nsl_c = (-10,20)\nax = Axis(f[5,1];ylabel = \"T₂ map : axial\",titlesize,ylabelsize,aspect=128/96)\nheatmap!(ax,circshift(reverse(fit_und[3][:,:,2],dims=2),sl_c);colorrange,colormap)\nhidedecorations!(ax,label=false)\nax = Axis(f[5,2],aspect=128/96)\nh=heatmap!(ax,circshift(reverse(fit_julia[3][:,:,2],dims=2),sl_c);colorrange,colormap)\nhidedecorations!(ax)\nif(isfile(path_bart))\n ax = Axis(f[5,3],aspect=128/96)\n heatmap!(ax,circshift(reverse(fit_bart[3][:,:,2],dims=2),sl_c);colorrange,colormap)\n hidedecorations!(ax)\nend\nColorbar(f[5,4],h,label = \"T₂ [ms]\",labelrotation=-pi/2,labelsize=20,height=Relative(0.85))\nrowgap!(f.layout,4,-35)\n\nf\nend\n\nsave(\"fig_bart_julia.png\",f)\nsave(\"fig_bart_julia.eps\",f)\nsave(\"fig_bart_julia.pdf\",f)","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"","category":"page"},{"location":"generated/examples/subspace_julia_epg/","page":"Generate figure 8","title":"Generate figure 8","text":"This page was generated using Literate.jl.","category":"page"},{"location":"fit_T2/#Fitting-the-data","page":"T₂ mapping","title":"Fitting the data","text":"","category":"section"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"The reconstruction and the fitting parts are totally independent.","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"The fitting functions expect a multidimensionnal-array with the echoes along the last dimension. The images should not be in complex, remember to use abs.(img).","category":"page"},{"location":"fit_T2/#Exponential-T_2-fitting-noise","page":"T₂ mapping","title":"Exponential T_2 fitting + noise","text":"","category":"section"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"In the publication we used an analytical model to fit the exponential decay of the echoes :","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"S(t) = sqrtleft(M_0 exp(-fractT_2)right)^2 + 2 L sigma_g^2","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"where L is the number of coil and sigma_g corresponds to the gaussian noise level on the image.","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"You can perform this fit with the following function :","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"T2Fit_exp_noise","category":"page"},{"location":"fit_T2/#Subspace_MESE.T2Fit_exp_noise","page":"T₂ mapping","title":"Subspace_MESE.T2Fit_exp_noise","text":" T2Fit_exp_noise(ima::Array{T,N}, t::AbstractVector{T}; removePoint::Bool=true, L::Int=1, mask = nothing) where {T<:Real,N}\n\nFit the relaxation parameters T2 with the equation : S(t) = sqrt(M_0 exp(-fractT2))^2 + 2 L sigma_g^2 where L est le nombre de canaux, et sigma_g le bruit gaussien sur les image\n\nArguments\n\nima::Array{T,N}: multi-dimensionnal images. Last dimension stores the temporal dimension\nt::AbstractVector{<:Real}: times vector in ms\np0=nothing: starting values for fit, if empty p0=[maximum(ima),30,maximum(ima)*0.1]\n\nKeywords\n\nremovePoint::Bool=true: remove the first point before fitting\nL::Int=1: Number of coil elements\nmask::\n\nReturns\n\nfit_params : parameter maps last dimension stores the following maps (M₀ , T₂ , σ)\n\nBibliography\n\nCárdenas-Blanco A, Tejos C, Irarrazaval P, Cameron I. Noise in magnitude magnetic\n\nresonance images. Concepts Magn Reson Part A [Internet]. 2008 Nov;32A(6):409?16. Available from: http://doi.wiley.com/10.1002/cmr.a.20124\n\nFeng Y, He T, Gatehouse PD, Li X, Harith Alam M, Pennell DJ, et al. Improved MRI R 2 *\n\nrelaxometry of iron-loaded liver with noise correction. Magn Reson Med [Internet]. 2013 Dec;70(6):1765?74. Available from: http://doi.wiley.com/10.1002/mrm.24607\n\n\n\n\n\n","category":"function"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"The keyword removePoint can be used to delete the first point in the TE vector as well as the first temporal volume in order to reduce the sensitivity of the fit to the stimulated echo.","category":"page"},{"location":"fit_T2/#EPG-T_2-fitting-noise-(WIP)","page":"T₂ mapping","title":"EPG T_2 fitting + noise (WIP)","text":"","category":"section"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"Another possibility is to fit the equation with an EPG model that, in addition to M_0/T_2/sigma, also fits the B_1 field.","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"With the current implementation, the fit is not robust enough and also takes too long to use on a 3D volume.","category":"page"},{"location":"fit_T2/","page":"T₂ mapping","title":"T₂ mapping","text":"T2Fit_epg_noise","category":"page"},{"location":"api/","page":"API","title":"API","text":"","category":"page"},{"location":"api/","page":"API","title":"API","text":"Modules = [Subspace_MESE]","category":"page"},{"location":"api/#Subspace_MESE.MESE_EPG-Union{Tuple{Ty}, Tuple{Ty, Ty, Ty, Ty, Int64, Ty, Int64}} where Ty<:AbstractFloat","page":"API","title":"Subspace_MESE.MESE_EPG","text":"MESE_EPG(T2::Ty,T1::Ty,TE::Ty,TR::Ty,ETL::Int,delta::Ty,dummy::Int) where Ty <: AbstractFloat\n\nGenerate the signal evolution of a Multi-Echo Spin-Echo sequence with an Extended Phase Graph model.\n\nInput :\n\n- `T2` : Transverse relaxation\n- `T1` : Longitudinal relaxation\n- `TE` : Echo Time\n- `TR` : Repetition time\n- `ETL` : Echo Train Length\n\nOutput :\n\n- Amplitude of each echoes\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.MESE_basis_EPG","page":"API","title":"Subspace_MESE.MESE_basis_EPG","text":"MESE_basis_EPG(NUM_BASIS::Int,TE,ETL::Int,T2_vec::Union{AbstractVector,AbstractFloat},B1_vec::Union{AbstractVector,AbstractFloat} = 1.0,T1_vec::Union{AbstractVector,AbstractFloat}=1000.0;TR = 1000.0,dummy::Int = 3)\n\nGenerate a temporal basis for a Multi-Echo Spin-Echo sequence with an Extended Phase Graph model for various value of T2/B1/T1\n\nstored as a vector in T2_vec/B1_vec/T1_vec.\n\nInput :\n\n- `NUM_BASIS::Int : Number of temporal basis to extract\n- `TE::AbstractFloat` : Cartesian acquisition with a fully-sampled center.\n- `ETL::Int` : Echo Train Length\n- `T2_vec::Union{AbstractVector,AbstractFloat}` : Vector of T₂ values used to generate the signal dictionnary \n- `B1_vec::Union{AbstractVector,AbstractFloat}` : Vector of B₁ values used to generate the signal dictionnary \n- `T1_vec::Union{AbstractVector,AbstractFloat}` : Vector of T₁ values used to generate the signal dictionnary\n\nKeyword :\n\n- `TR` : Repetition time\n- `dummy` : Number of dummy scan before extracting the signal value\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `epg_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nB1_vec = 0.8:0.01:1.0\nT2_vec = 1.0:1.0:2000.0\nT1_vec = 1000.0 #can also be a float\nTE = 7.0\nTR = 1000.0\ndummy=3\nETL = 50\nNUM_BASIS = 6\n\nbasis_epg, epg_dict =MESE_basis_EPG(NUM_BASIS,TE,ETL,T2_vec,B1_vec,T1_vec;TR=TR,dummy=dummy)\n\n\n\n\n\n","category":"function"},{"location":"api/#Subspace_MESE.MESE_basis_exp-Tuple{Int64, AbstractFloat, Int64, AbstractVector}","page":"API","title":"Subspace_MESE.MESE_basis_exp","text":" MESE_basis_exp(NUM_BASIS::Int,TE::AbstractFloat,ETL::Int, T2_vec::AbstractVector;removeFirstPoint::Bool=false)\n\nGenerate a temporal basis for a Multi-Echo Spin-Echo sequence with an exponential model.for various value of T2 stored as a vector in T2_vec. The first point of the echo train can be removed from the dictionnary with the keyword removeFirstPoint to minimize the effect of stimulated echoes. \n\nInput :\n\n- `NUM_BASIS::Int : Number of temporal basis to extract\n- `TE::AbstractFloat` : Cartesian acquisition with a fully-sampled center.\n- `ETL::Int` : Echo Train Length\n- `T2_vec::AbstractVector` : Vector of T₂ values used to generate the signal dictionnary\n\nKeyword :\n\n- `removeFirstPoint::Bool=False` : Remove the first point of the dictionnary before the svd\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `exp_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nT2_vec = 1.0:1.0:2000.0\nTE = 7.0\nETL = 50\nNUM_BASIS = 6\n\nbasis_exp,exp_dict = MESE_basis_exp(NUM_BASIS,TE,ETL,T2_vec)\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.RawAcquisitionData_MESE-Tuple{MRIFiles.BrukerFile}","page":"API","title":"Subspace_MESE.RawAcquisitionData_MESE","text":"RawAcquisitionData_MESE(b::BrukerFile)\n\nConvert a Bruker dataset acquired with the aMESECS sequence into a RawAcquisitionData object compatible with the MRIReco functions.\n\nInput : - b::BrukerFile\n\nOutput : - raw::RawAcquisitionData\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.RawAcquisitionData_MESE_PV360-Tuple{MRIFiles.BrukerFile}","page":"API","title":"Subspace_MESE.RawAcquisitionData_MESE_PV360","text":"RawAcquisitionData_MESE_PV360(b::BrukerFile)\n\nConvert a Bruker dataset acquired with the aMESECS_360 sequence into a RawAcquisitionData object compatible with the MRIReco functions.\n\nInput : - b::BrukerFile\n\nOutput : - raw::RawAcquisitionData\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.RawAcquisitionData_MESE_PV6-Tuple{MRIFiles.BrukerFile}","page":"API","title":"Subspace_MESE.RawAcquisitionData_MESE_PV6","text":"RawAcquisitionData_MESE_PV6(b::BrukerFile)\n\nConvert a Bruker dataset acquired with the aMESECS sequence into a RawAcquisitionData object compatible with the MRIReco functions.\n\nInput : - b::BrukerFile\n\nOutput : - raw::RawAcquisitionData\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.T2Fit_epg_noise-Union{Tuple{N}, Tuple{T}, Tuple{Array{T, N}, AbstractVector{T}}, Tuple{Array{T, N}, AbstractVector{T}, Any}, Tuple{Array{T, N}, AbstractVector{T}, Any, Any}} where {T<:Real, N}","page":"API","title":"Subspace_MESE.T2Fit_epg_noise","text":"T2Fit_epg_noise(ima::Array{T,N}, t::AbstractVector{T},T1=1000.0,TE=7.0; EPGthresh = 1e-5,p0=nothing,mask = nothing) where {T<:Real,N}\n\nWIP\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.T2Fit_exp_noise-Union{Tuple{N}, Tuple{T}, Tuple{Array{T, N}, AbstractVector{T}}} where {T<:Real, N}","page":"API","title":"Subspace_MESE.T2Fit_exp_noise","text":" T2Fit_exp_noise(ima::Array{T,N}, t::AbstractVector{T}; removePoint::Bool=true, L::Int=1, mask = nothing) where {T<:Real,N}\n\nFit the relaxation parameters T2 with the equation : S(t) = sqrt(M_0 exp(-fractT2))^2 + 2 L sigma_g^2 where L est le nombre de canaux, et sigma_g le bruit gaussien sur les image\n\nArguments\n\nima::Array{T,N}: multi-dimensionnal images. Last dimension stores the temporal dimension\nt::AbstractVector{<:Real}: times vector in ms\np0=nothing: starting values for fit, if empty p0=[maximum(ima),30,maximum(ima)*0.1]\n\nKeywords\n\nremovePoint::Bool=true: remove the first point before fitting\nL::Int=1: Number of coil elements\nmask::\n\nReturns\n\nfit_params : parameter maps last dimension stores the following maps (M₀ , T₂ , σ)\n\nBibliography\n\nCárdenas-Blanco A, Tejos C, Irarrazaval P, Cameron I. Noise in magnitude magnetic\n\nresonance images. Concepts Magn Reson Part A [Internet]. 2008 Nov;32A(6):409?16. Available from: http://doi.wiley.com/10.1002/cmr.a.20124\n\nFeng Y, He T, Gatehouse PD, Li X, Harith Alam M, Pennell DJ, et al. Improved MRI R 2 *\n\nrelaxometry of iron-loaded liver with noise correction. Magn Reson Med [Internet]. 2013 Dec;70(6):1765?74. Available from: http://doi.wiley.com/10.1002/mrm.24607\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.basis_calibration-Union{Tuple{D}, Tuple{T}, Tuple{Int64, MRIBase.AcquisitionData{T, D}, NTuple{D, Int64}}} where {T, D}","page":"API","title":"Subspace_MESE.basis_calibration","text":"basis_calibration(NUM_BASIS::Int,acq::AcquisitionData{T,D},crop_size::NTuple{D,Int}) where {T,D}\n\nk_bart = kDataCart(acq); \n\nExtract a temporal basis from a low-resolution images reconstructed using a fully sampled area at the center of the k-space with a size crop_size. \n\nInput :\n\n- `NUM_BASIS::Int : Number of temporal basis to extract\n- `acq::AcquisitionData` : Cartesian acquisition with a fully-sampled center.\n- `crop_size::NTuple{D,Int})` : size of the central part of k-space used\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `calib_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nb = BrukerFile(\"path/to/dataset\")\n\nraw = RawAcquisitionData_MESE(b)\nacq = AcquisitionData(raw,OffsetBruker = true);\n\nbasis, calib_dict = MESE_basis_calibration(acq,(15,15,15),6)\n\n\n\n\n\n","category":"method"},{"location":"api/#Subspace_MESE.subspace_bart_reconstruction-Tuple{MRIBase.AcquisitionData, Dict{Symbol, Any}, AbstractString}","page":"API","title":"Subspace_MESE.subspace_bart_reconstruction","text":"subspace_bart_reconstruction(acq::AcquisitionData,params::Dict{Symbol,Any},bart_path::AbstractString)\n\nReconstruction of the accelerated MESE sequence with BART.\n\nInput :\n\n- `acq::AcquisitionData` : Cartesian acquisition with a fully-sampled center.\n- `params::Dict{Symbol,Any}` : size of the central part of k-space used\n- `bart_path::AbstractString` : path to the BART executable library\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `calib_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nb = BrukerFile(\"path/to/dataset\")\n\nraw = RawAcquisitionData_MESE(b)\nacq = AcquisitionData(raw,OffsetBruker = true);\n\nbasis, calib_dict = MESE_basis_calibration(acq,(15,15,15),6)\n\n\n\n\n\n","category":"method"},{"location":"building_basis/#Generate-Subspaces","page":"Subspace generation","title":"Generate Subspaces","text":"","category":"section"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"This package implements 3 different subspaces :","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Exponential\nExtended Phase Graph (EPG)\nCalibration","category":"page"},{"location":"building_basis/#How-to-build-a-subspace","page":"Subspace generation","title":"How to build a subspace","text":"","category":"section"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"The 3 methods are based on the same concept :","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Generate a dictionary with the signal evolution at each echo time signal_dict","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Apply a Singular Value Decomposition on it","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"svd_obj = svd(signal_dict)","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"and then crop to the desired subspace dimension","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"basis = ComplexF32.(svd_obj.V)[:, 1:NUM_BASIS]","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"This concept can be applied to create your own subspace, for example directly from echo images.","category":"page"},{"location":"building_basis/#Difference-between-the-3-methods","page":"Subspace generation","title":"Difference between the 3 methods","text":"","category":"section"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Exponential and EPG subspace generate a dictionary with the signal evolution of the Multi-Echo Spin-Echo sequence for various T_2 (or B_1 for the EPG case).","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"The calibration subspace reconstructs low-resolution images at each Echo Time with the fully sampled area of the k-space.","category":"page"},{"location":"building_basis/#Exponential-subspace","page":"Subspace generation","title":"Exponential subspace","text":"","category":"section"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"MESE_basis_exp","category":"page"},{"location":"building_basis/#Subspace_MESE.MESE_basis_exp","page":"Subspace generation","title":"Subspace_MESE.MESE_basis_exp","text":" MESE_basis_exp(NUM_BASIS::Int,TE::AbstractFloat,ETL::Int, T2_vec::AbstractVector;removeFirstPoint::Bool=false)\n\nGenerate a temporal basis for a Multi-Echo Spin-Echo sequence with an exponential model.for various value of T2 stored as a vector in T2_vec. The first point of the echo train can be removed from the dictionnary with the keyword removeFirstPoint to minimize the effect of stimulated echoes. \n\nInput :\n\n- `NUM_BASIS::Int : Number of temporal basis to extract\n- `TE::AbstractFloat` : Cartesian acquisition with a fully-sampled center.\n- `ETL::Int` : Echo Train Length\n- `T2_vec::AbstractVector` : Vector of T₂ values used to generate the signal dictionnary\n\nKeyword :\n\n- `removeFirstPoint::Bool=False` : Remove the first point of the dictionnary before the svd\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `exp_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nT2_vec = 1.0:1.0:2000.0\nTE = 7.0\nETL = 50\nNUM_BASIS = 6\n\nbasis_exp,exp_dict = MESE_basis_exp(NUM_BASIS,TE,ETL,T2_vec)\n\n\n\n\n\n","category":"function"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"In the publication, the subspace is extracted from a dictionary generated with a range of T_2 from 1 ms to 2000 ms with a step of 1 ms.","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Other approachs can be used :","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"a logarithmic repartition of T_2 \nextracting from a fully acquisition the distribution of T_2 and then generate from that distribution the dictionary (Tamir et al, MRM,2017)","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Let's take a look at the first 6 subspace vectors from a linear repartition :","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"using Subspace_MESE\n\nT2_vec = 1.0:1.0:2000.0\nTE = 7.0\nETL = 50\nNUM_BASIS = 6\n\nbasis_exp,_=MESE_basis_exp(NUM_BASIS,TE,ETL,T2_vec)\n\nusing CairoMakie\ncolor = Makie.wong_colors()\nf = Figure()\nax=Axis(f[1,1])\nfor b in 1:6\n lines!(ax,abs.(basis_exp[:,b]),color=color[b],label = \"Basis n°$b\")\nend\nhidedecorations!(ax)\naxislegend(ax)\nf","category":"page"},{"location":"building_basis/#EPG-subspace","page":"Subspace generation","title":"EPG subspace","text":"","category":"section"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"MESE_basis_EPG","category":"page"},{"location":"building_basis/#Subspace_MESE.MESE_basis_EPG","page":"Subspace generation","title":"Subspace_MESE.MESE_basis_EPG","text":"MESE_basis_EPG(NUM_BASIS::Int,TE,ETL::Int,T2_vec::Union{AbstractVector,AbstractFloat},B1_vec::Union{AbstractVector,AbstractFloat} = 1.0,T1_vec::Union{AbstractVector,AbstractFloat}=1000.0;TR = 1000.0,dummy::Int = 3)\n\nGenerate a temporal basis for a Multi-Echo Spin-Echo sequence with an Extended Phase Graph model for various value of T2/B1/T1\n\nstored as a vector in T2_vec/B1_vec/T1_vec.\n\nInput :\n\n- `NUM_BASIS::Int : Number of temporal basis to extract\n- `TE::AbstractFloat` : Cartesian acquisition with a fully-sampled center.\n- `ETL::Int` : Echo Train Length\n- `T2_vec::Union{AbstractVector,AbstractFloat}` : Vector of T₂ values used to generate the signal dictionnary \n- `B1_vec::Union{AbstractVector,AbstractFloat}` : Vector of B₁ values used to generate the signal dictionnary \n- `T1_vec::Union{AbstractVector,AbstractFloat}` : Vector of T₁ values used to generate the signal dictionnary\n\nKeyword :\n\n- `TR` : Repetition time\n- `dummy` : Number of dummy scan before extracting the signal value\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `epg_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nB1_vec = 0.8:0.01:1.0\nT2_vec = 1.0:1.0:2000.0\nT1_vec = 1000.0 #can also be a float\nTE = 7.0\nTR = 1000.0\ndummy=3\nETL = 50\nNUM_BASIS = 6\n\nbasis_epg, epg_dict =MESE_basis_EPG(NUM_BASIS,TE,ETL,T2_vec,B1_vec,T1_vec;TR=TR,dummy=dummy)\n\n\n\n\n\n","category":"function"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"In order to generate the EPG subspace, more parameters need to be defined. Specifically, the range of B_1 to be expected in the acquisition might be larger for surfacic transmit coil than for volumic coils that have a homogeneous B_1^+ field.","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"Of note, B1vec, T2vec, T1vec can also be passed as float values rather than vectors. In the publication, the T1vec was fixed to 1000 ms.","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"using Subspace_MESE\nB1_vec = 0.8:0.01:1.0\nT2_vec = 1.0:1.0:2000.0\nT1_vec = 1000.0 #can also be a vector of float\nTE = 7.0\nTR = 1000.0\ndummy=3\nETL = 50\nNUM_BASIS = 6\n\nbasis_epg,_=MESE_basis_EPG(NUM_BASIS,TE,ETL,T2_vec,B1_vec,T1_vec;TR=TR,dummy=dummy)\n\nusing CairoMakie\ncolor = Makie.wong_colors()\nf = Figure()\nax=Axis(f[1,1])\nfor b in 1:6\n lines!(ax,abs.(basis_epg[:,b]),color=color[b],label = \"Basis n°$b\")\nend\nhidedecorations!(ax)\naxislegend(ax)\nf","category":"page"},{"location":"building_basis/#Calibration-subspace","page":"Subspace generation","title":"Calibration subspace","text":"","category":"section"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"basis_calibration","category":"page"},{"location":"building_basis/#Subspace_MESE.basis_calibration","page":"Subspace generation","title":"Subspace_MESE.basis_calibration","text":"basis_calibration(NUM_BASIS::Int,acq::AcquisitionData{T,D},crop_size::NTuple{D,Int}) where {T,D}\n\nk_bart = kDataCart(acq); \n\nExtract a temporal basis from a low-resolution images reconstructed using a fully sampled area at the center of the k-space with a size crop_size. \n\nInput :\n\n- `NUM_BASIS::Int : Number of temporal basis to extract\n- `acq::AcquisitionData` : Cartesian acquisition with a fully-sampled center.\n- `crop_size::NTuple{D,Int})` : size of the central part of k-space used\n\nOutput :\n\n- `basis` : Matrix of size (ETL,NUM_BASIS)\n- `calib_dict` : Dictionnary of signal used to generate the basis\n\nExample :\n\nb = BrukerFile(\"path/to/dataset\")\n\nraw = RawAcquisitionData_MESE(b)\nacq = AcquisitionData(raw,OffsetBruker = true);\n\nbasis, calib_dict = MESE_basis_calibration(acq,(15,15,15),6)\n\n\n\n\n\n","category":"function"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"The calibration subspace reconstructs low-resolution images from a fully sampled area of the k-space. ","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"You can generate the subspace from the acquired accelerated acquisition with the parameter crop_size equal to the size of the fully sampled area of the k-space.","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"But you can also generate the subspace from a different fully acquisition (for example on a control acquisition)","category":"page"},{"location":"building_basis/","page":"Subspace generation","title":"Subspace generation","text":"b = BrukerFile(\"path/to/dataset\")\n\nraw = RawAcquisitionData_MESE(b)\nacq = AcquisitionData(raw,OffsetBruker = true);\n\nbasis,_ = MESE_basis_calibration(acq,(15,15,15),6)","category":"page"},{"location":"installation/#Unregistered-package-Installation","page":"Installation","title":"Unregistered package Installation","text":"","category":"section"},{"location":"installation/","page":"Installation","title":"Installation","text":"You can install the package in any project with the following command :","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"launch julia with the command julia\nenter the Julia package manager by typing ] in the REPL. (the REPL should turn in blue)\nif you want to activate an environment, type : activate . (otherwise the package will be installed in the global environment)\nIn order to add our unregistered package, type add https://github.com/CRMSB/PAPER_subspace_MESE\nif you want to use the package : using Subspace_MESE","category":"page"},{"location":"installation/#Reproducing-figure-8","page":"Installation","title":"Reproducing figure 8","text":"","category":"section"},{"location":"installation/","page":"Installation","title":"Installation","text":"In order to reproduce figure 8, you need to :","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"compile the BART toolbox : https://mrirecon.github.io/bart/ (you can skip this step if you don't want to plot the BART reconstruction). After compilation/installation you can check the library path with which bart\ndownload the dataset : https://zenodo.org/records/10610639 and extract the zip file.\ndownload the current repository : git clone https://github.com/CRMSB/PAPER_subspace_MESE\nOpen a terminal and move to the docs folder in this repository\nedit the script in docs/lit/example/subspace_julia_epg.jl and put the correct path in the variable \nline 27 : path_raw should point to the bruker folder 10\nline 30 : path_bart should point to the compiled bart library\nlaunch julia in the docs folder with this command in the terminal: julia --project -t auto\nrun the literate example :\nusing Pkg\nPkg.add(url=\"https://github.com/CRMSB/PAPER_subspace_MESE\")\nPkg.instantiate()\ninclude(\"lit/examples/subspace_julia_epg.jl\")","category":"page"},{"location":"installation/","page":"Installation","title":"Installation","text":"The figure will be saved as fig_bart_julia.png in the docs folder.","category":"page"},{"location":"","page":"Home","title":"Home","text":"CurrentModule = Subspace_MESE","category":"page"},{"location":"#Subspace_MESE","page":"Home","title":"Subspace_MESE","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Documentation for the Subspace_MESE package, which implements the necessary functions to convert and reconstruct an accelerated 3D Multi-Echo Spin-Echo sequence with a subspace reconstruction in order to generate T2 maps.","category":"page"},{"location":"#How-to-give-credit","page":"Home","title":"How to give credit","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"If you use this package please acknowledge us by citing : https://doi.org/10.1002/mrm.30146","category":"page"},{"location":"","page":"Home","title":"Home","text":"Additionally, if you use the sequence available in the MR sequence folder, please contact us to sign the sequence transfer agreement : aurelien.trotier@rmsb.u-bordeaux.fr","category":"page"},{"location":"#Bruker-Acquisition","page":"Home","title":"Bruker Acquisition","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"This package is compatible with the sequence : a_MESE_CS which is available as a binary file in the folder : MR_sequence","category":"page"},{"location":"","page":"Home","title":"Home","text":"The sequence is only available for the version PV6.0.1, PV360:3.5 and 3.6. The protocol used for an acceleration factor of CS=8 is also available.","category":"page"},{"location":"#Reconstruction-Pipeline","page":"Home","title":"Reconstruction Pipeline","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"The reconstruction pipeline includes 4 steps :","category":"page"},{"location":"","page":"Home","title":"Home","text":"Conversion of the Bruker rawdataset to a MRIReco compatible format (/src/bruker_sequence.jl)\nGeneration of the subspace (/src/build_basis.jl)\nReconstruction of the subspace coefficient and the virtual echo images\nT2 fitting (/src/fit_T2_MESE.jl)","category":"page"},{"location":"","page":"Home","title":"Home","text":"(Image: Reconstruction Pipeline)","category":"page"},{"location":"","page":"Home","title":"Home","text":"Those steps are described in their dedicated sections.","category":"page"},{"location":"#Example","page":"Home","title":"Example","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Reproduction of figure 8 can be performed at this link","category":"page"},{"location":"reconstruction_subspace/#Compressed-sensing-reconstruction-with-a-subspace-constrained","page":"Subspace Reconstruction","title":"Compressed sensing reconstruction with a subspace constrained","text":"","category":"section"},{"location":"reconstruction_subspace/#Background","page":"Subspace Reconstruction","title":"Background","text":"","category":"section"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"The main idea is to solve the following problem :","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"min_alpha frac12y - E Phi_K alpha^2_2 + lambdaW(alpha)_1","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"where y is the k-space data, E is the encoding operator regrouping the FFT operator and the coil sensitvity operator. Phi_K is the subspace cropped to the first K temporal dimensions, alpha is the subspace coefficient maps and W corresponds to the Wavelet Operator which is applied on alpha.","category":"page"},{"location":"reconstruction_subspace/#Julia-implementation","page":"Subspace Reconstruction","title":"Julia implementation","text":"","category":"section"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"The subspace reconstruction was implemented as part of MRIReco.jl package. An example in the MRIReco.jl package can be found here.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"The reconstruction works on an AcquisitionData object (previously converted from the Bruker raw dataset). Because it is a combined parallel imaging and compressed sensing approach, we have to estimate the coil sensitivity map.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"using Subspace_MESE\nusing Subspace_MESE.MRIFiles\nusing Subspace_MESE.MRIReco\nusing Subspace_MESE.MRICoilSensitivities\n\nb=BrukerFile(\"path/to/dataset/\")\nraw = RawAcquisitionData_MESE(b)\nacq = AcquisitionData(raw,OffsetBruker = true);\n\ncoilsens = espirit(acq,eigThresh_2=0.0);\nbasis,dico = basis_calibration(6,acq,(15,15,15))","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"From that point, we need to define a Dict structure (here named params) to store and pass the MRIReco reconstruction parameters.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"params = Dict{Symbol,Any}()\nparams[:reconSize] = acq.encodingSize\n\n# Subspace \nparams[:reco] = \"multiCoilMultiEchoSubspace\"\nparams[:senseMaps] = coilsens\nparams[:basis] = basis\n\n# Compressed sensing transform\nparams[:regularization] = \"L1\"\nparams[:sparseTrafo] = \"Wavelet\" #sparse trafo\nparams[:λ] = Float32(0.01)\n\n# Algorithm parameters\nparams[:solver] = \"fista\"\nparams[:iterations] = 30\nparams[:normalizeReg] = true","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"params[:reco] = \"multiCoilMultiEchoSubspace\" means that it is a subspace reconstruction with parallel imaging and needs the fields params[:senseMaps] and params[:basis]","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"The remaining parameters are linked to the algorithm used, here a wavelet transform + L1 regularization with a FISTA algorithm and 30 iterations.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"To perform the reconstruction we can now call the function :","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"alpha = reconstruction(acq, params);","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"The results of the reconstruction is not directly the echo images but the subspace coefficient maps. In order to get the virtual echo images, the subspace needs to be applied on this coefficient maps.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"im_TE = abs.(applySubspace(α, basis))","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"warning: Warning\nThe reconstruction part might evolve due to changes in the MRIReco package and its dependencies, particularly RegularizedLeastSquares.jl","category":"page"},{"location":"reconstruction_subspace/#Comparison-with-BART","page":"Subspace Reconstruction","title":"Comparison with BART","text":"","category":"section"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"All the figures (except some parts of figure 8) from the publication were generated using a reconstruction from BART. For comparison purpose, the reconstruction is also available in this package and detailed below.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"You need to compile the BART toolbox : https://mrirecon.github.io/bart/ and pass as an argument the path to the executable BART library in the subspace_bart_reconstruction function.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"This package uses the wrapper BartIO.jl to send the data back and forth between JULIA and BART.","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"using Subspace_MESE.BartIO\n\nparams = Dict{Symbol,Any}()\nparams[:iterations] = 60\nparams[:λ] = 0.01\nparams[:basis]=basis\n\nim_sub_bart,im_TE_bart = subspace_bart_reconstruction(acq,params,\"/home/CODE/bart/bart\")","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"If you need more control over the reconstruction parameters for BART, take a look at the function (only 20 lines)","category":"page"},{"location":"reconstruction_subspace/","page":"Subspace Reconstruction","title":"Subspace Reconstruction","text":"note: Note\nThe regularization parameters between MRIReco.jl and BART are different and need to be adjusted manually. This can be explained by some low-level differences in the FISTA algorithm / Wavelet transform and also due to scaling of the data prior to the algorithm.","category":"page"},{"location":"convert/#Conversion-from-Bruker-dataset-to-MRIReco.jl-object","page":"Convert data","title":"Conversion from Bruker dataset to MRIReco.jl object","text":"","category":"section"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"After acquisition, you can convert the Bruker dataset to a RawAcquisitionData with the specific function RawAcquisitionData_MESE(b::BrukerFile). Conversion is mostly performed with MRIReco/MRIBase and MRIFiles functions. ","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"We need to import them first :","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"using Subspace_MESE\nusing Subspace_MESE.MRIFiles\nusing Subspace_MESE.MRIReco\n\nb=BrukerFile(\"path/to/dataset/20230317_085834_AT_MSME_CS_44_1_1/10\")\nraw = RawAcquisitionData_MESE(b)","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"The RawAcquisitionData object is an implementation of the MRD format. After that point the remaining function are purely in the MRIReco.jl package. ","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"In order to perform the reconstruction, the raw object needs to be converted into an AcquisitionData object with the following command :","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"acq = AcquisitionData(raw,OffsetBruker = true);","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"The keyword OffsetBruker is equal to true in order to correct the Field-Of-View offset along the phase and partition directions (specific to Bruker).","category":"page"},{"location":"convert/#Direct-reconstruction","page":"Convert data","title":"Direct reconstruction","text":"","category":"section"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"From that point the user should take a look at the MRIReco.jl documentation in order to perfom the reconstruction. ","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"A direct reconstruction can be performed with : ","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"params = Dict{Symbol,Any}()\nparams[:reconSize] = acq.encodingSize\nparams[:reco] = \"direct\"\n\nim_u = reconstruction(acq, params);","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"This returns images which can be artifacted in the case of an undersampled acquisitioncan.","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"We can combine the different coil elements with a sum of squares :","category":"page"},{"location":"convert/","page":"Convert data","title":"Convert data","text":"using Subspace_MESE.MRICoilSensitivities\nim_u_sos = mergeChannels(im_u)","category":"page"}] }