Compare ADCs
The apparent diffusion coefficient (ADC) may be sufficient to describe the signal attenuation for small $b$-values. SpinDoctor comes with multiple approaches for computing or estimating the ADC for a ScalarGradient
$\vec{g}(t) = f(t) g \vec{d}$:
- Using the free diffusion coefficient $\vec{d}^\mathsf{T} \mathbf{D} \vec{d}$, which represents unrestricted diffusion in the absence of boundaries;
- Computing the short diffusion time approximation for the ADC
- Fitting the log-signal obtained by solving the BTPDE for different $b$-values
- Solving a homogenized model (HADC) assuming negligible permeability
- Using the matrix formalism effective diffusion tensor
In this example we will compare the different approaches.
Building a biological model
We start by loading SpinDoctor and a Makie plotting backend.
using SpinDoctor
using LinearAlgebra
if haskey(ENV, "GITHUB_ACTIONS")
using CairoMakie
else
using GLMakie
end
Here we create a recipe for five stacked plates with isotropic diffusion tensors. They should allow for free diffusion in the horizontal direction, but a rather restricted vertical diffusion with the permeable membranes.
ncell = 5
setup = PlateSetup(;
name = "Plates",
width = 50.0,
depth = 50.0,
heights = fill(5.0, ncell),
bend = 0.0,
twist = 0.0,
refinement = 10.0,
)
coeffs = coefficients(
setup;
D = [0.002 * I(3) for _ = 1:ncell],
T₂ = fill(Inf, ncell),
ρ = fill(1.0, ncell),
κ = (; interfaces = fill(1e-4, ncell - 1), boundaries = fill(0.0, ncell)),
γ = 2.67513e-4,
)
(D = StaticArrays.SMatrix{3, 3, Float64, 9}[[0.002 0.0 0.0; 0.0 0.002 0.0; 0.0 0.0 0.002], [0.002 0.0 0.0; 0.0 0.002 0.0; 0.0 0.0 0.002], [0.002 0.0 0.0; 0.0 0.002 0.0; 0.0 0.0 0.002], [0.002 0.0 0.0; 0.0 0.002 0.0; 0.0 0.0 0.002], [0.002 0.0 0.0; 0.0 0.002 0.0; 0.0 0.0 0.002]], T₂ = [Inf, Inf, Inf, Inf, Inf], κ = [0.0001, 0.0001, 0.0001, 0.0001, 0.0, 0.0, 0.0, 0.0, 0.0], ρ = ComplexF64[1.0 + 0.0im, 1.0 + 0.0im, 1.0 + 0.0im, 1.0 + 0.0im, 1.0 + 0.0im], γ = 0.000267513)
We then proceed to build the geometry and finite element mesh.
mesh, = create_geometry(setup; recreate = true)
plot_mesh(mesh)
The mesh looks good, so we may then proceed to assemble the biological model and the associated finite element matrices.
model = Model(; mesh, coeffs...)
matrices = assemble_matrices(model);
We may also compute some useful quantities, including a scalar diffusion coefficient from the diffusion tensors.
volumes = get_cmpt_volumes(model.mesh)
D_avg = 1 / 3 * tr.(model.D)' * volumes / sum(volumes)
ncompartment = length(model.mesh.points)
5
The gradient pulse sequence will be a PGSE with both vertical and horizontal components. This allows for both restricted vertical diffusion and almost unrestricted horizontal diffusion. The different approaches should hopefully confirm this behaviour.
dir = [1.0, 0.0, 1.0]
profile = PGSE(2500.0, 4000.0)
b = 1000
g = √(b / int_F²(profile)) / model.γ
gradient = ScalarGradient(dir, profile, g)
ScalarGradient{Float64}([0.7071067811865475, 0.0, 0.7071067811865475], PGSE{Float64}(2500.0, 4000.0), 0.8402604538082508)
Computing the ADC using different methods
Short term approximation
A simple model for the ADC is given by the short term approximation.
adc_sta_cmpts = compute_adc_sta(model, gradient)
adc_sta = volumes'adc_sta_cmpts / sum(volumes)
0.0009218342324169138
Fitting the ADC
A more robust approach is to directly fit the BTPDE signal to a series of b-values. This is however more computationally expensive. We start by building a set of gradients.
bvalues = 0:400:4000
gvalues = map(b -> √(b / int_F²(profile)) / coeffs.γ, bvalues)
gradients = [ScalarGradient(gradient.dir, gradient.profile, g) for g ∈ gvalues]
11-element Vector{ScalarGradient{Float64}}:
ScalarGradient{Float64}([0.7071067811865476, 0.0, 0.7071067811865476], PGSE{Float64}(2500.0, 4000.0), 0.0)
ScalarGradient{Float64}([0.7071067811865476, 0.0, 0.7071067811865476], PGSE{Float64}(2500.0, 4000.0), 0.5314273723601551)
ScalarGradient{Float64}([0.7071067811865476, 0.0, 0.7071067811865476], PGSE{Float64}(2500.0, 4000.0), 0.7515517974080282)
ScalarGradient{Float64}([0.7071067811865476, 0.0, 0.7071067811865476], PGSE{Float64}(2500.0, 4000.0), 0.9204592094606131)
ScalarGradient{Float64}([0.7071067811865476, 0.0, 0.7071067811865476], PGSE{Float64}(2500.0, 4000.0), 1.0628547447203103)
ScalarGradient{Float64}([0.7071067811865476, 0.0, 0.7071067811865476], PGSE{Float64}(2500.0, 4000.0), 1.1883077297013998)
ScalarGradient{Float64}([0.7071067811865476, 0.0, 0.7071067811865476], PGSE{Float64}(2500.0, 4000.0), 1.3017258976304167)
ScalarGradient{Float64}([0.7071067811865476, 0.0, 0.7071067811865476], PGSE{Float64}(2500.0, 4000.0), 1.4060246671574907)
ScalarGradient{Float64}([0.7071067811865476, 0.0, 0.7071067811865476], PGSE{Float64}(2500.0, 4000.0), 1.5031035948160565)
ScalarGradient{Float64}([0.7071067811865476, 0.0, 0.7071067811865476], PGSE{Float64}(2500.0, 4000.0), 1.5942821170804655)
ScalarGradient{Float64}([0.7071067811865476, 0.0, 0.7071067811865476], PGSE{Float64}(2500.0, 4000.0), 1.6805209076165015)
The solve_multigrad
function computes the magnetization for each gradient. Since the gradients are interval-wise constant, we can use a specialized solver.
btpde = BTPDE(; model, matrices)
solver = IntervalConstantSolver(; θ = 0.5, timestep = 5.0)
ξ, = solve_multigrad(btpde, gradients, solver)
(Vector{ComplexF64}[[0.9999999999999936 + 0.0im, 0.9999999999999972 + 0.0im, 1.000000000000004 + 0.0im, 1.0000000000000082 + 0.0im, 0.9999999999999843 + 0.0im, 0.9999999999999838 + 0.0im, 1.0000000000000024 + 0.0im, 0.9999999999999895 + 0.0im, 1.0000000000000324 + 0.0im, 1.0000000000000386 + 0.0im … 0.9999999999999807 + 0.0im, 1.0000000000000286 + 0.0im, 1.0000000000000167 + 0.0im, 1.0000000000000133 + 0.0im, 1.0000000000000304 + 0.0im, 1.0000000000000022 + 0.0im, 1.0000000000000464 + 0.0im, 0.9999999999999787 + 0.0im, 0.9999999999999768 + 0.0im, 0.999999999999989 + 0.0im], [0.5977093159286848 - 0.5212855742458541im, 0.7649137260733314 + 0.18083322156669476im, 0.76706820483919 + 0.18097808449533032im, 0.5971934095985018 - 0.521179665548462im, 0.7205743933102189 - 0.2850182090627342im, 0.6538211760436635 + 0.4154274315331699im, 0.655507518601017 + 0.4166510460088704im, 0.7194631424482016 - 0.2819810275691136im, 0.602399296354735 - 0.14024018375691996im, 0.7622034963722791 + 0.17601704470660814im … 0.6091101877992796 + 0.038986812961620564im, 0.7143131037069859 - 0.32929392203945024im, 0.6108072108015844 + 0.04271203107849156im, 0.7134279647661738 - 0.3310001657612641im, 0.6108363322988695 + 0.06051910847735788im, 0.6105855769009015 + 0.040833406273510765im, 0.7342115381504134 - 0.2995497905582932im, 0.608315250324133 + 0.06055235167395974im, 0.6074506563884778 + 0.04463801285376593im, 0.6058767669227116 + 0.04299965159268734im], [0.3616577037879585 - 0.5171766530070663im, 0.5953362632847652 + 0.18060402255718488im, 0.5980028251246875 + 0.18163335416307447im, 0.3610657021641772 - 0.5171642049551832im, 0.5353061203898191 - 0.279132512930941im, 0.4347894137125226 + 0.42076206488371165im, 0.4368210736532671 + 0.4229579390224687im, 0.5348447103735372 - 0.274306851845055im, 0.3590874258134872 - 0.1160251903039248im, 0.5896975624271824 + 0.1764446318888496im … 0.3672766235220036 + 0.030260943962937978im, 0.5217771387286322 - 0.3399636481987724im, 0.36913376051149577 + 0.03290883934065136im, 0.5215862472539302 - 0.3413240561511281im, 0.3700593657165282 + 0.04852606874051809im, 0.36884011063407474 + 0.030911207849842623im, 0.5513040115506335 - 0.30947939776454436im, 0.36617092720837846 + 0.048182499816723345im, 0.3624930071967299 + 0.03422792556986103im, 0.36258616690478657 + 0.03195835422832891im], [0.2270202563679616 - 0.45313675713373697im, 0.4719390777940532 + 0.1549896271057798im, 0.4744259573382586 + 0.15634087428333354im, 0.22635237248978268 - 0.45383309623971246im, 0.4115653068042398 - 0.23694097854634685im, 0.2967277739649263 + 0.3745393455540567im, 0.29890831648243654 + 0.37705258121370333im, 0.41217564988207017 - 0.2314670886224868im, 0.2127804582361081 - 0.0816953129477241im, 0.4638394367017856 + 0.15196255921029772im … 0.22018415956869802 + 0.019685512475045155im, 0.39159550516157254 - 0.30656427777185113im, 0.2216929301785081 + 0.020902705147290992im, 0.39248450424703046 - 0.30780163226918567im, 0.223203470351191 + 0.03226988563781324im, 0.22130170807145794 + 0.019248703526072653im, 0.42462626968042566 - 0.2784199891497431im, 0.21898313265925956 + 0.03236625636036422im, 0.21382624169044193 + 0.02016776001232807im, 0.21500189786607793 + 0.019527149196126563im], [0.15131920930525788 - 0.3835454610564857im, 0.38111805421312017 + 0.12398458189647686im, 0.38328300170753915 + 0.12512059925953425im, 0.15012338490665186 - 0.38516453956679736im, 0.3270593182294788 - 0.18981462512906397im, 0.20941526114002518 + 0.31986210332155796im, 0.21191150413944876 + 0.3223377557715091im, 0.3285481334176475 - 0.18446604515157217im, 0.12545299260718543 - 0.053652838548101815im, 0.37130124142549836 + 0.12210250357076037im … 0.131423458525998 + 0.011921689732445504im, 0.3030046449795233 - 0.2632565386248352im, 0.13248406120107914 + 0.012027975212348182im, 0.304872785330412 - 0.2645855363158369im, 0.13416066578837527 + 0.01942958284371919im, 0.13200266486585358 + 0.01076315701778547im, 0.33613475298087364 - 0.2376040640966269im, 0.1302126172447929 + 0.020222829643749118im, 0.12546378897849797 + 0.009449536755548452im, 0.12617521000654 + 0.010952304470323995im], [0.10906762417441962 - 0.3225983045854455im, 0.3133630938372537 + 0.09442150006717968im, 0.31531448502878523 + 0.09498827936979126im, 0.10696278314443326 - 0.3249495932559853im, 0.2675767689064725 - 0.1470164251492355im, 0.15373245288901752 + 0.2696432160202772im, 0.15676117557729055 + 0.2719834643807514im, 0.26956478529197786 - 0.14218290156238722im, 0.07355488298669653 - 0.03383905151150991im, 0.30255088763632887 + 0.09363515066073849im … 0.07810962763773831 + 0.007012334422450546im, 0.24212050964729692 - 0.22140890729419502im, 0.07879680604650365 + 0.006515649776416448im, 0.2447080308529858 - 0.2229165692114462im, 0.08026951227042448 + 0.010804420297606287im, 0.07826569598246223 + 0.00549702453702567im, 0.2735964144370821 - 0.1976975927048394im, 0.07693671854673137 + 0.012160369969635546im, 0.07375785190938121 + 0.003032479986302074im, 0.07312400960450467 + 0.00609307198843739im], [0.08557040565414682 - 0.2727605842291319im, 0.2620145003805592 + 0.06865019512734491im, 0.2639480832992934 + 0.06846393397639376im, 0.08240456046749961 - 0.2755024765223716im, 0.22426736198521224 - 0.1108904080641834im, 0.11771529089783182 + 0.2273103481374863im, 0.12143430759703702 + 0.22956769741858302im, 0.22639388494411727 - 0.10669625702681164im, 0.04285905973315855 - 0.02073830412877729im, 0.2507986045785362 + 0.0689039102977847im … 0.04623629839743627 + 0.004108098241647412im, 0.19967345557177288 - 0.18480226972159755im, 0.046665491138520275 + 0.0034530190180632326im, 0.20269956330888803 - 0.18647745346898878im, 0.047657867670166915 + 0.00549420666724496im, 0.046122558066843795 + 0.002510819620423923im, 0.22869882345479306 - 0.16242436707490066im, 0.04512413633417303 + 0.007158519705734752im, 0.04381937765434669 - 2.8753560784887264e-5im, 0.04181351316566594 + 0.003766798477105141im], [0.07249565353481228 - 0.2329691008400218im, 0.22239871388894056 + 0.04719100084688328im, 0.22451930583858407 + 0.04619420047339159im, 0.06830216088344072 - 0.23578101086071226im, 0.19162904298480282 - 0.08138801894837877im, 0.09391431460223844 + 0.1929136868433151im, 0.09840165977716274 + 0.19521194993641255im, 0.19362159722258895 - 0.07781208627835957im, 0.024823510334938955 - 0.012399480544584505im, 0.2112326015990056 + 0.048422918693549026im … 0.027294535672999096 + 0.0024495226238122427im, 0.16949224503136406 - 0.15421889655808294im, 0.027564717836652753 + 0.0019113860640348629im, 0.1727095582332929 - 0.1559926796000144im, 0.02791518085094815 + 0.0024265802355285266im, 0.027027491450737063 + 0.0009245361358531483im, 0.19580061769860876 - 0.13269298287640996im, 0.026242114087928203 + 0.004174350590189911im, 0.02656537744496004 - 0.000999977992213206im, 0.02365985618293788 + 0.0028923457751953907im], [0.06515406055548333 - 0.20135244279771355im, 0.19123482756748925 + 0.0297985315867714im, 0.193720830048337 + 0.028020234673387736im, 0.06006345285013277 - 0.20399914066366523im, 0.16621277786372174 - 0.05769345713329798im, 0.07771509713491308 + 0.16537651214816934im, 0.08297611848296738 + 0.1678651299215335im, 0.16789054497102215 - 0.05465259562527627im, 0.014324903889251506 - 0.007226707727310308im, 0.18045632280758686 + 0.03194283296515293im … 0.016115975949628283 + 0.0015272675903823339im, 0.14748726090404393 - 0.12924748693623628im, 0.01630119557289216 + 0.0012168494443450504im, 0.15069983377354332 - 0.13102390417992418im, 0.015959202912211916 + 0.0007591808861119764im, 0.01576846034722462 + 0.00012524372754167025im, 0.17108845955526872 - 0.10824415388040409im, 0.015109522591232672 + 0.0024391028965459584im, 0.01659127498678406 - 0.0009034474418900147im, 0.013386648079380694 + 0.0027273679799972215im], [0.060919729087758015 - 0.1761192267911773im, 0.1662217604520049 + 0.015940800695206744im, 0.16920997230827 + 0.013465663707866924im, 0.05509099460007245 - 0.17845129781993077im, 0.1458282979501004 - 0.038835241832207594im, 0.06627853318113083 + 0.1433844326180044im, 0.0722576014592093 + 0.14621248726180508im, 0.14708168228337082 - 0.03623069888147565im, 0.008293604729739416 - 0.004086852200012975im, 0.1560764913464721 + 0.01893376944633im … 0.009562874618392342 + 0.001030173003679393im, 0.13096314260010503 - 0.1090687366929667im, 0.009720020906883313 + 0.0009492053622458835im, 0.13402798670877997 - 0.11074543533775462im, 0.008722357162391293 - 8.062547282870765e-5im, 0.009180721060021801 - 0.0002616539546784502im, 0.1519985309895316 - 0.08838567989803761im, 0.008589305504220508 + 0.0014466042974030204im, 0.010747057581810802 - 0.00040636086537890637im, 0.007749877439264939 + 0.0028387431482773296im], [0.058330116763950585 - 0.15579909580792195im, 0.14574677608016884 + 0.005023221504024666im, 0.14932763987169043 + 0.001967643860732103im, 0.05191384080600001 - 0.15772911504227755im, 0.12906240684708997 - 0.02390887509490032im, 0.05787002375999848 + 0.12572704142856936im, 0.06446210916008757 + 0.12902633076535033im, 0.12983011951545023 - 0.02164664736044437im, 0.004893231258478956 - 0.0022281906547702134im, 0.13640570694292586 + 0.008807446216628916im … 0.005738857079302933 + 0.0007728334377361414im, 0.11815256104178949 - 0.09280313813904703im, 0.005914058804732725 + 0.0008718658936365784im, 0.1209738035962497 - 0.09428408719473182im, 0.0043525010265811495 - 0.0004530630954141871im, 0.0053547092458768345 - 0.0004459752912066915im, 0.13681629091582173 - 0.07232995937730025im, 0.004793210294382928 + 0.0008822343145665456im, 0.007229519054661425 + 0.00012034140388857767im, 0.004773166407633703 + 0.003010432361620303im]], [24.833155155181885, 22.005048990249634, 19.898781061172485, 19.957324981689453, 19.41311001777649, 19.355464935302734, 19.472800970077515, 19.430912971496582, 18.882198095321655, 18.871180057525635, 18.98899006843567])
The signals can be computed from the magnetization fields.
signals = [compute_signal(matrices.M, ξ) for ξ ∈ ξ]
signals_cmpts = [compute_signal.(matrices.M_cmpts, split_field(model.mesh, ξ)) for ξ ∈ ξ]
11-element Vector{Vector{ComplexF64}}:
[12500.000000000036 + 0.0im, 12499.99999999992 + 0.0im, 12499.999999999913 + 0.0im, 12499.999999999893 + 0.0im, 12499.999999999998 + 0.0im]
[7908.75667724861 - 567.0897152892503im, 7694.441257524089 - 3.224789888122647im, 7686.459345077631 + 0.182190607078752im, 7692.533190480926 + 3.3562780140755066im, 7910.478459490787 + 566.7760365562169im]
[4994.923116572435 - 460.86145053845064im, 4725.799214091538 + 1.4874803600828814im, 4712.554310907857 + 0.34048256878169525im, 4720.231632038438 - 1.0286198000554307im, 4998.296701630244 + 460.0621074096388im]
[3171.949646453355 - 315.7661559582654im, 2925.3513753942752 + 5.2392304950541835im, 2912.280287632255 + 0.3610360261498151im, 2916.4673594908822 - 4.717465169600583im, 3175.8464170360085 + 314.88335460666104im]
[2035.7725307144292 - 202.20832247958054im, 1837.2072518581306 + 6.127923491369751im, 1826.5271739967757 + 0.319553748965987im, 1826.4104066181749 - 5.683909587300237im, 2039.2641001828235 + 201.44475482654548im]
[1326.994603620626 - 126.07030582459743im, 1176.8214929971746 + 5.275739937031959im, 1168.709149256925 + 0.24613971154876957im, 1165.7117951522764 - 4.930377170644803im, 1329.6461512325745 + 125.47880334666112im]
[883.4327358470576 - 78.39481164412254im, 772.7566618566673 + 3.920142540772227im, 766.6727583129704 + 0.1494736078462502im, 762.5586959450052 - 3.6480922500452606im, 885.1227820685474 + 77.97328774554917im]
[604.4799914287447 - 49.44083689943679im, 522.894885034812 + 2.7038485616635373im, 518.2005269582824 + 0.04556003987515922im, 514.2994019188791 - 2.4744986147305696im, 605.2257191793459 + 49.16592691262841im]
[427.7909808213488 - 31.973438500268216im, 366.422093894432 + 1.812294798834654im, 362.5691511430605 - 0.04744157098224289im, 359.6692089754026 - 1.603294663476268im, 427.6565565656715 + 31.811879935891618im]
[314.7117095383769 - 21.305474504527197im, 266.95140843736095 + 1.2180950136334578im, 263.51062280632925 - 0.11811882908991267im, 261.98656614249137 - 1.0165584811503954im, 313.7689765493809 + 21.22205680113369im]
[241.2759071890961 - 14.605128829275843im, 202.57100065096955 + 0.8348273395236645im, 199.21936305697258 - 0.16360887936227586im, 199.18607377670304 - 0.634865196386575im, 239.5900584012075 + 14.568775565500834im]
Fitting the ADC is straightforward.
adc_fit = fit_adc(bvalues, signals)
adc_fit_cmpts =
[fit_adc(bvalues, [s[icmpt] for s ∈ signals_cmpts]) for icmpt = 1:ncompartment]
5-element Vector{Float64}:
0.0011263098412238682
0.0011981247035952702
0.0011984851414936183
0.001198006549661825
0.0011260215072748012
Homogenized ADC model
The HADC-model uses homogenization and assumes negligible permeability between the compartments. This does require solving an ODE involving all the degrees of freedom.
hadc = HADC(; model, matrices)
adc_homogenized_cmpts = solve(hadc, gradient)
adc_homogenized = volumes'adc_homogenized_cmpts / sum(volumes)
0.0010652640390143562
Matrix Formalism
If a Laplace eigendecomposition is available, the HADC can be approximated with little additional computational expense.
laplace = Laplace(; model, matrices, neig_max = 400)
lap_eig = solve(laplace)
(values = [1.2185839489911229e-17, 6.218630333211627e-6, 7.910433131954157e-6, 7.910755217532168e-6, 1.4149445229185232e-5, 1.4150565812798932e-5, 1.584862790456446e-5, 2.2103756778852548e-5, 2.3606472948032338e-5, 3.1550727181500624e-5 … 0.0008193911610800552, 0.0008215137080710397, 0.0008236713683601019, 0.0008242491335551407, 0.0008254195079051181, 0.0008261283885063043, 0.0008273043752859631, 0.0008291998354012451, 0.0008319406840304292, 0.0008354984009843569], funcs = [0.003999999999996791 -0.0054557345067856025 … 0.011890377939146195 -0.003154928628568066; 0.004000000000002934 -0.005448061972496463 … -0.004235693382370668 -0.005090922825587665; … ; 0.004000000000000522 0.005391790333021098 … 0.005855756512284026 -0.000941847155932718; 0.00400000000000058 0.005392380928566916 … -0.008898117672865972 0.0016030612626752566], moments = [[-2.788307779111321e-13 3.8265720657768704e-5 … -0.002579416198598368 0.00047936711775596955; 3.826572065768197e-5 -0.0001770115894670285 … -0.0001534441127361702 -0.0003810866417003995; … ; -0.002579416198598538 -0.0001534441127360696 … 0.09402836556885938 0.211884669832186; 0.0004793671177558186 -0.0003810866417003375 … 0.21188466983218612 -0.27260452639346366], [3.419486915845482e-14 2.826856254423138e-5 … 0.00035101125541478484 0.0015398705514115402; 2.8268562544238318e-5 -8.777228345917959e-5 … -0.0007796430156714745 -0.00018959068268394053; … ; 0.0003510112554147536 -0.0007796430156713358 … 0.21721995412231046 0.09743433988490216; 0.0015398705514117553 -0.00018959068268396134 … 0.097434339884902 0.05791107659543239], [1.1235457009206584e-13 7.084124714588285 … 0.0002920418521086196 0.00022079024172878825; 7.084124714588283 -0.00016029432016595457 … -0.0007429334752234729 0.0008992906882692511; … ; 0.0002920418521085849 -0.0007429334752234451 … 1.174533834778186 -0.6375825153842201; 0.00022079024172880907 0.0008992906882692997 … -0.6375825153842203 -0.4687460808426511]], massrelax = [0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0])
An effective diffusion tensor can be computed.
D_mf = compute_mf_diffusion_tensor(model.mesh, matrices.M, lap_eig, gradient)
3×3 Matrix{Float64}:
0.00180812 -4.99349e-8 -1.10896e-8
-4.99349e-8 0.00180823 1.02731e-8
-1.10896e-8 1.02731e-8 0.000326084
We observe that $D_{x x}$ and $D_{y y}$ are very close to the intrinsic diffusion coefficient $D = 0.002$, which confirms that diffusion in the horizontal direction is almost unrestricted. $D_{z z}$ is significantly smaller, confirming the presence of membranes along the vertical direction.
In particular, we may deduce the MF-ADC in our direction.
adc_mf = dir'D_mf * dir / dir'dir
0.0010670907197978371
Comparing results
Compartment ADCs
Here we make a comparison between the compartment ADCs. For MF, only a global ADC was computed.
n = ncompartment
fig = Figure()
ax = Axis(fig[1, 1];
xticks = (1:4, ["STA", "Fit BTPDE", "HADC", "MF"]),
ylabel = "ADC / D",
title = "Compartment ADCs",
)
barplot!(ax, fill(1, n), adc_sta_cmpts ./ D_avg; dodge = 1:n)
barplot!(ax, fill(2, n), adc_fit_cmpts ./ D_avg; dodge = 1:n)
barplot!(ax, fill(3, n), adc_homogenized_cmpts ./ D_avg; dodge = 1:n)
barplot!(ax, [4], [adc_mf / D_avg])
fig
The STA and HADC are the same for all compartments, as they consider them separately and all the compartments have the same size. The fitted ADC is larger for the three inner compartments, as they all have permeable membranes both below and above, in contrast to the top and bottom compartments that have hard walls.
Signal attenuation
We may also inspect the resulting signal attenuations.
fig = Figure()
ax = Axis(fig[1,1]; xlabel = "b", yscale = log10, title = "Signal attenuation")
lines!(ax, [0, bvalues[end]], [1, exp(-adc_sta * bvalues[end])]; linestyle = :dash, label = "ADC STA")
lines!(ax, [0, bvalues[end]], [1, exp(-adc_fit * bvalues[end])]; linestyle = :dash, label = "ADC Fit")
lines!(ax, [0, bvalues[end]], [1, exp(-adc_homogenized * bvalues[end])]; linestyle = :dash, label = "HADC")
lines!(ax, [0, bvalues[end]], [1, exp(-adc_mf * bvalues[end])]; linestyle = :dash, label = "ADC MF")
lines!(ax, [0, bvalues[end]], [1, exp(-D_avg * bvalues[end])]; linestyle = :dash, label = "Free diffusion")
scatterlines!(ax, bvalues, abs.(signals) ./ abs(signals[1]); label = "BTPDE Signal")
axislegend(ax)
fig
We observe the following:
- The exact signal starts to visually deviate from the log-linear regime after $b = 2000$. For higher $b$-values, the ADC is no longer sufficient to describe the attenuation, as higher order terms can no longer be neglected.
- The fit-ADC signal coincides with the exact signal for the lowest $b$-values. This makes sense since that is how this ADC was obtained to begin with. This is considered to be the "reference" ADC.
- The free diffusion signal attenuates more thant the exact signal by many orders of magnitude, which confirms the presence of restrictive membranes and boundaries in the gradient direction.
- The HADC signal attenuates less than the exact signal, as it assumes a more severe restriction with impermeable membranes.
- The MF-ADC signal coincides with the HADC signal, as the former is simply an MF approximation of the latter.
This page was generated using Literate.jl.