Global fit
First, we load the required packages and include some Helper functions
include("helper_functions.jl")load all T₁-mapping methods:
include("T1_mapping_methods.jl")and initialize the plot:
p = plot([0, 2], [0, 2], xlabel="simulated T1 (s)", ylabel="literature T1 (s)", legend=:topleft, label=:none, xlim=(0.5, 1.1), ylim=(0.5, 1.1))
marker_list = [(seq_type_i == :IR) ? (:circle) : ((seq_type_i == :LL) ? (:cross) : ((seq_type_i == :vFA) ? (:diamond) : ((seq_type_i == :SR) ? (:dtriangle) : (:x)))) for seq_type_i in seq_type]Mono-exponential model
We simulate the mono-exponential model as an MT model with a vanishing semi-solid spin pool. In this case, the underlying MT model is irrelevant, and we choose Graham's model for speed purposes:
MT_model = Graham()The following parameters are hard-coded, except for R1f, which serves as an initialization for the global fit.
m0s = 0
R1f = 1 / 1.084  # 1/s
R1s = R1f        # 1/s
R2f = 1 / 0.0769 # 1/s
T2s = 0
Rx = 0           # 1/s
ω0 = 0
B1 = 1We define a model for the global fit. It takes the global set of parameters p as an input and returns a vector of T₁ estimates that correspond to the T₁ mapping methods described by the vector T1_functions
function model(iseq, p)
    R1f = p[1]
    T1 = similar(iseq, Float64)
    Threads.@threads for i in eachindex(iseq)
        T1[i] = T1_functions[iseq[i]](m0s, R1f, R2f, Rx, R1s, T2s)
    end
    return T1
endPerform the fit and calculate the simulated T₁:
fit_mono = curve_fit(model, 1:length(T1_literature), T1_literature, [R1f], x_tol=1e-3)
T1_simulated = model(1:length(T1_literature), fit_mono.param)For this model, the single fitted global parameter is:
T1f = 1 / fit_mono.param[1] # s0.8894530882606787The following plot visualizes the quality of the fit and replicates Fig. 1 in the manuscript:
scatter!(p, T1_simulated, T1_literature, label="mono-exponential model", markershape=marker_list, hover=seq_name)Akaike (AIC) and Bayesian (BIC) information criteria
The information criteria depend on the number of measurements:
n = length(T1_literature)25the number of parameters:
k = length(fit_mono.param)1and the squared sum of the residuals:
RSS = norm(fit_mono.resid)^20.36165228007243183As the AIC and BIC are only informative in the difference between two models, we use the mono-exponential model as the reference:
AIC_mono = n * log(RSS / n) + 2k-103.8986976484162BIC_mono = n * log(RSS / n) + k * log(n)-102.679821823548In this case, ΔAIC is by definition zero:
ΔAIC = n * log(RSS / n) + 2k - AIC_mono0.0as is ΔBIC:
ΔBIC = n * log(RSS / n) + k * log(n) - BIC_mono0.0Graham's MT model (unconstrained R₁ˢ)
MT_model = Graham()The following parameters are hard-coded, except for m0s, R1f, and R1s, which serve as an initialization for the global fit.
m0s = 0.25
R1f = 1 / 1.84   # 1/s
R1s = 1 / 0.34   # 1/s
R2f = 1 / 0.0769 # 1/s
T2s = 12.5e-6    # s
Rx = 13.6        # 1/s
ω0 = 0
B1 = 1We define a model for the global fit. It takes the global set of parameters p as an input and returns a vector of T₁ estimates that correspond to the T₁ mapping methods described by the vector T1_functions
function model(iseq, p)
    m0s, R1f, R1s = p
    T1 = similar(iseq, Float64)
    Threads.@threads for i in eachindex(iseq)
        T1[i] = T1_functions[iseq[i]](m0s, R1f, R2f, Rx, R1s, T2s)
    end
    return T1
endPerform the fit and calculate the simulated T₁:
fit_Graham = curve_fit(model, 1:length(T1_literature), T1_literature, [m0s, R1f, R1s], x_tol=1e-3)
T1_simulated = model(1:length(T1_literature), fit_Graham.param)For this model, the fitted global set of parameters is:
m0s = fit_Graham.param[1]0.19446378469746337T1f = 1 / fit_Graham.param[2] # s2.026087604670749T1s = 1 / fit_Graham.param[3] # s0.24535283941180797The following plot visualizes the quality of the fit and replicates Fig. 1 in the manuscript:
scatter!(p, T1_simulated, T1_literature, label="Graham's model (unconstrained R₁ˢ)", markershape=marker_list, hover=seq_name)Note that clicking on a legend entry removes the fit from the plot. A double click on an entry selects only this particular fit.
Akaike (AIC) and Bayesian (BIC) information criteria
The information criteria depend on the number of measurements n, the number of parameters k, and the squared sum of the residuals RSS:
n = length(T1_literature)25k = length(fit_Graham.param)3RSS = norm(fit_Graham.resid)^20.14656258643959397With this information, we can calculate the AIC difference to the mono-exponential model:
ΔAIC = n * log(RSS / n) + 2k - AIC_mono-18.580766237337997and similarly for the BIC:
ΔBIC = n * log(RSS / n) + k * log(n) - BIC_mono-16.1430145876016Sled's MT model (unconstrained R₁ˢ)
MT_model = Sled()The following parameters are hard-coded, except for m0s, R1f, and R1s, which serve as an initialization for the global fit.
m0s = 0.25
R1f = 1 / 1.84   # 1/s
R1s = 1 / 0.34   # 1/s
R2f = 1 / 0.0769 # 1/s
T2s = 12.5e-6    # s
Rx = 13.6        # 1/s
ω0 = 0
B1 = 1We define a model for the global fit. It takes the global set of parameters p as an input and returns a vector of T₁ estimates that correspond to the T₁ mapping methods described by the vector T1_functions
function model(iseq, p)
    m0s, R1f, R1s = p
    T1 = similar(iseq, Float64)
    Threads.@threads for i in eachindex(iseq)
        T1[i] = T1_functions[iseq[i]](m0s, R1f, R2f, Rx, R1s, T2s)
    end
    return T1
endPerform the fit and calculate the simulated T₁:
fit_Sled = curve_fit(model, 1:length(T1_literature), T1_literature, [m0s, R1f, R1s], x_tol=1e-3)
T1_simulated = model(1:length(T1_literature), fit_Sled.param)For this model, the fitted global set of parameters is:
m0s = fit_Sled.param[1]0.09938220860166001T1f = 1 / fit_Sled.param[2] # s1.7045103081206696T1s = 1 / fit_Sled.param[3] # s0.11768341516509102The following plot visualizes the quality of the fit and replicates Fig. 1 in the manuscript:
scatter!(p, T1_simulated, T1_literature, label="Sled's model (unconstrained R₁ˢ)", markershape=marker_list, hover=seq_name)Note that clicking on a legend entry removes the fit from the plot. A double click on an entry selects only this particular fit.
Akaike (AIC) and Bayesian (BIC) information criteria
The information criteria depend on the number of measurements n, the number of parameters k, and the squared sum of the residuals RSS:
n = length(T1_literature)25k = length(fit_Sled.param)3RSS = norm(fit_Sled.resid)^20.13996520972762952With this information, we can calculate the AIC difference to the mono-exponential model:
ΔAIC = n * log(RSS / n) + 2k - AIC_mono-19.73223270329035and similarly for the BIC:
ΔBIC = n * log(RSS / n) + k * log(n) - BIC_mono-17.29448105355395Generalized Bloch model (R₁ˢ = R₁ᶠ)
MT_model = gBloch()The following parameters are hard-coded, except for m0s and R1f, which serve as an initialization for the global fit.
m0s = 0.139
R1f = 1 / 1.084  # 1/s
R1s = 1          # 1/s
R2f = 1 / 0.0769 # 1/s
T2s = 12.5e-6    # s
Rx = 23          # 1/s
ω0 = 0
B1 = 1We define a model for the global fit. It takes the global set of parameters p as an input and returns a vector of T₁ estimates that correspond to the T₁ mapping methods described by the vector T1_functions
function model(iseq, p)
    m0s, R1f = p
    R1s = R1f
    T1 = similar(iseq, Float64)
    Threads.@threads for i in eachindex(iseq)
        T1[i] = T1_functions[iseq[i]](m0s, R1f, R2f, Rx, R1s, T2s)
    end
    return T1
endPerform the fit and calculate the simulated T₁:
fit_constr = curve_fit(model, 1:length(T1_literature), T1_literature, [m0s, R1f], x_tol=1e-3)
T1_simulated = model(1:length(T1_literature), fit_constr.param)For this model, the fitted global set of parameters is:
m0s = fit_constr.param[1]0.12881793551863777T1f = 1 / fit_constr.param[2] # s0.9742290010278117The following plot visualizes the quality of the fit and replicates Fig. 1 in the manuscript:
scatter!(p, T1_simulated, T1_literature, label="generalized Bloch model (R₁ˢ = R₁ᶠ constraint)", markershape=marker_list, hover=seq_name)Note that clicking on a legend entry removes the fit from the plot. A double click on an entry selects only this particular fit.
Akaike (AIC) and Bayesian (BIC) information criteria
The information criteria depend on the number of measurements n, the number of parameters k, and the squared sum of the residuals RSS:
n = length(T1_literature)25k = length(fit_constr.param)2RSS = norm(fit_constr.resid)^20.17054658474454984With this information, we can calculate the AIC difference to the mono-exponential model:
ΔAIC = n * log(RSS / n) + 2k - AIC_mono-16.791867855021792and similarly for the BIC:
ΔBIC = n * log(RSS / n) + k * log(n) - BIC_mono-15.5729920301536Generalized Bloch model (unconstrained R₁ˢ)
MT_model = gBloch()The following parameters are hard-coded, except for m0s, R1f, and R1s, which serve as an initialization for the global fit.
m0s = 0.25
R1f = 1 / 1.84   # 1/s
R1s = 1 / 0.34   # 1/s
R2f = 1 / 0.0769 # 1/s
T2s = 12.5e-6    # s
Rx = 13.6        # 1/s
ω0 = 0
B1 = 1We define a model for the global fit. It takes the global set of parameters p as an input and returns a vector of T₁ estimates that correspond to the T₁ mapping methods described by the vector T1_functions
function model(iseq, p)
    m0s, R1f, R1s = p
    T1 = similar(iseq, Float64)
    Threads.@threads for i in eachindex(iseq)
        T1[i] = T1_functions[iseq[i]](m0s, R1f, R2f, Rx, R1s, T2s)
    end
    return T1
endPerform the fit and calculate the simulated T₁:
fit_uncon = curve_fit(model, 1:length(T1_literature), T1_literature, [m0s, R1f, R1s], x_tol=1e-3)
T1_simulated = model(1:length(T1_literature), fit_uncon.param)For this model, the fitted global set of parameters is:
m0s = fit_uncon.param[1]0.20903106717408043T1f = 1 / fit_uncon.param[2] # s2.063020626243208T1s = 1 / fit_uncon.param[3] # s0.262550660513381The following plot visualizes the quality of the fit and replicates Fig. 1 in the manuscript:
scatter!(p, T1_simulated, T1_literature, label="generalized Bloch model (unconstrained R₁ˢ)", markershape=marker_list, hover=seq_name)Note that clicking on a legend entry removes the fit from the plot. A double click on an entry selects only this particular fit.
Akaike (AIC) and Bayesian (BIC) information criteria
The information criteria depend on the number of measurements n, the number of parameters k, and the squared sum of the residuals RSS:
n = length(T1_literature)25k = length(fit_uncon.param)3RSS = norm(fit_uncon.resid)^20.11479629307483916With this information, we can calculate the AIC difference to the mono-exponential model:
ΔAIC = n * log(RSS / n) + 2k - AIC_mono-24.6881001209606and similarly for the BIC:
ΔBIC = n * log(RSS / n) + k * log(n) - BIC_mono-22.2503484712242Data analysis
The span of T₁ estimates in the literature is
extrema(T1_literature)(0.64, 1.0855)and the coefficient of variation is
variation(T1_literature)0.1408807728048427Median absolute deviation
In the paper, the median absolute deviation from the mean value is used, as it is more robust to outliers compared to the mean absolute deviation or the standard deviation. Note, however, that the median absolute deviation of the mono-exponential fit is dominated by an outlier, artificially inflating the corresponding reduction.
A mono-exponential model explains the following fraction of the T₁ variability in the literature:
1 - mad(fit_mono.resid; center=mean(fit_mono.resid)) / mad(T1_literature; center=mean(T1_literature))0.07118935312824093Graham's spectral model without constraints on R₁ᶠ explains the following fraction of the T₁ variability in the literature:
1 - mad(fit_Graham.resid; center=mean(fit_Graham.resid)) / mad(T1_literature; center=mean(T1_literature))0.6071335860151669Sled's model without constraints on R₁ᶠ explains the following fraction of the T₁ variability in the literature:
1 - mad(fit_Sled.resid; center=mean(fit_Sled.resid)) / mad(T1_literature; center=mean(T1_literature))0.5567822162017504The generalized Bloch model constrained by R₁ˢ = R₁ᶠ explains the following fraction of the T₁ variability in the literature:
1 - mad(fit_constr.resid; center=mean(fit_constr.resid)) / mad(T1_literature; center=mean(T1_literature))0.4684203732531683The generalized Bloch model without constraints on R₁ᶠ explains the following fraction of the T₁ variability in the literature:
1 - mad(fit_uncon.resid; center=mean(fit_uncon.resid)) / mad(T1_literature; center=mean(T1_literature))0.6171961683507089Mean absolute deviation
For comparison, the mean absolute deviation is analyzed: A mono-exponential model explains the following fraction of the T₁ variability in the literature:
1 - mean(abs.(fit_mono.resid .- mean(fit_mono.resid))) / mean(abs.(T1_literature .- mean(T1_literature)))0.023426403041203026Graham's spectral model without constraints on R₁ᶠ explains the following fraction of the T₁ variability in the literature:
1 - mean(abs.(fit_Graham.resid .- mean(fit_Graham.resid))) / mean(abs.(T1_literature .- mean(T1_literature)))0.4834831199140681Sled's model without constraints on R₁ᶠ explains the following fraction of the T₁ variability in the literature:
1 - mean(abs.(fit_Sled.resid .- mean(fit_Sled.resid))) / mean(abs.(T1_literature .- mean(T1_literature)))0.48265447199825884The generalized Bloch model constrained by R₁ˢ = R₁ᶠ explains the following fraction of the T₁ variability in the literature:
1 - mean(abs.(fit_constr.resid .- mean(fit_constr.resid))) / mean(abs.(T1_literature .- mean(T1_literature)))0.42795873321794164The generalized Bloch model without constraints on R₁ᶠ explains the following fraction of the T₁ variability in the literature:
1 - mean(abs.(fit_uncon.resid .- mean(fit_uncon.resid))) / mean(abs.(T1_literature .- mean(T1_literature)))0.5261587981865726Standard deviation
For comparison, the standard deviation is analyzed: A mono-exponential model explains the following fraction of the T₁ variability in the literature:
1 - std(fit_mono.resid) / std(T1_literature)0.01826093355907199Graham's spectral model without constraints on R₁ᶠ explains the following fraction of the T₁ variability in the literature:
1 - std(fit_Graham.resid) / std(T1_literature)0.37502858305844344Sled's spectral model without constraints on R₁ᶠ explains the following fraction of the T₁ variability in the literature:
1 - std(fit_Sled.resid) / std(T1_literature)0.38924942271187124The generalized Bloch model constrained by R₁ˢ = R₁ᶠ explains the following fraction of the T₁ variability in the literature:
1 - std(fit_constr.resid) / std(T1_literature)0.32587111172659133The generalized Bloch model without constraints on R₁ᶠ explains the following fraction of the T₁ variability in the literature:
1 - std(fit_uncon.resid) / std(T1_literature)0.4468849451044564