Solve BTPDE

We start by loading SpinDoctor and a Makie plotting backend.

using SpinDoctor
using LinearAlgebra
using Random

if haskey(ENV, "GITHUB_ACTIONS")
    using CairoMakie
else
    using GLMakie
end

Set random seed for reproducibility

Random.seed!(123)
Random.TaskLocalRNG()

The built in geometry recipes allow for making various cell configurations. We here consider the case of three twisted axons immersed in an extracellular space (ECS). The axons are extruded from a 2D ground setup consisting of three random disks.

setup = CylinderSetup(;
    ncell = 3,
    ecs = ConvexHullECS(; margin = 2.0),
    height = 40.0,
    bend = 0.0,
    twist = π / 4,
)
CylinderSetup{Float64, ConvexHullECS{Float64}}
  groundsetup: DiskSetup{Float64, ConvexHullECS{Float64}}
  refinement: Float64 Inf
  height: Float64 40.0
  bend: Float64 0.0
  twist: Float64 0.7853981633974483

We also define parameters for the cell compartments and ECS. The required parameters are:

  • 3D Diffusion tensors D (we here use an isotropic coefficient)
  • T2-relaxation times T₂
  • Initial spin densities ρ
  • Permeabilities κ

The parameters D, T₂, and ρ are defined for each compartment, while κ is defined for each interface and outer boundary. The DiskSetup allows for multiple layers in each cell (here nlayer = 1), so cell and cell_boundaries are arrays of length nlayer = 1, while cell_interfaces is of length nlayer - 1 = 0.

coeffs = coefficients(
    setup;
    D = (; cell = [0.002 * I(3)], ecs = 0.002 * I(3)),
    T₂ = (; cell = [Inf], out = Inf, ecs = Inf),
    ρ = (; cell = [1.0], out = 1.0, ecs = 1.0),
    κ = (; cell_interfaces = zeros(0), cell_boundaries = [0.0], cell_ecs = 1e-4, ecs = 0.0),
    γ = 2.67513e-4,
)
(D = [[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], κ = [0.0, 0.0, 0.0001, 0.0, 0.0001, 0.0001, 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], γ = 0.000267513)

The following line creates a random cell configuration for our cylinder setup, generates a surface triangulation and calls TetGen to create a tetrahedral finite element mesh. The compartments and boundaries will be ordered in the same way as coeffs.

mesh, surfaces, cells = create_geometry(setup)
(SpinDoctor.FEMesh{Float64, 3}([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10  …  1061, 1062, 1064, 1066, 1102, 1106, 1107, 1111, 1113, 1118], [13, 14, 15, 16, 17, 18, 19, 20, 21, 22  …  1050, 1051, 1097, 1098, 1099, 1100, 1103, 1104, 1105, 1109], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39  …  1038, 1039, 1094, 1095, 1096, 1101, 1108, 1110, 1112, 1114], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10  …  1089, 1090, 1091, 1092, 1093, 1115, 1116, 1117, 1119, 1120]], [[15.082718079328439 15.352979394778533 … 8.951502240400457 10.805043881484655; -0.877699437546676 1.1751390607938879 … 7.048908264966403 3.6467824945986953; -20.0 -20.0 … 11.25 -6.25], [5.566461744061371 5.98781998613544 … 0.43441965610525357 -0.02563698116508828; 2.0644025213185593 4.0618578866720005 … 4.190163956819523 4.204390404839309; -20.0 -20.0 … -20.0 -14.414328232678379], [-6.038998579123932 -5.671742422014201 … -9.097074573563216 -10.516569589158443; -2.5745701021829923 -0.5930331991229953 … -3.5277112181337125 -0.7198994633381002; -20.0 -20.0 … 2.5 -20.0], [15.082718079328439 15.352979394778533 … 5.509007211397983 3.954806529363884; -0.877699437546676 1.1751390607938879 … -4.4931455537572536 -5.88647187996765; -20.0 -20.0 … -1.7739273663246702 -16.90175538468711]], [Matrix{Int64}(undef, 3, 0) Matrix{Int64}(undef, 3, 0) … Matrix{Int64}(undef, 3, 0) Matrix{Int64}(undef, 3, 0); Matrix{Int64}(undef, 3, 0) Matrix{Int64}(undef, 3, 0) … Matrix{Int64}(undef, 3, 0) Matrix{Int64}(undef, 3, 0); Matrix{Int64}(undef, 3, 0) Matrix{Int64}(undef, 3, 0) … [12 9 … 15 14; 13 10 … 1 15; 248 248 … 248 248] Matrix{Int64}(undef, 3, 0); Matrix{Int64}(undef, 3, 0) Matrix{Int64}(undef, 3, 0) … Matrix{Int64}(undef, 3, 0) [107 757 … 1090 598; 108 455 … 719 592; 825 460 … 1093 1098]], [[95 117 … 53 179; 166 66 … 55 56; 91 120 … 115 180; 198 196 … 197 197], [215 152 … 260 107; 33 151 … 258 256; 34 253 … 279 258; 277 275 … 280 280], [82 142 … 172 168; 146 64 … 49 111; 90 144 … 170 170; 242 242 … 246 246], [153 409 … 211 711; 161 408 … 719 712; 332 410 … 712 719; 342 1024 … 1093 1093]]), (points = [14.27876664852878 13.742868263666535 … -7.419914275384653 -15.047497514861513; 4.932903284952767 6.932903284952767 … 8.252873729197479 -0.8063742161941281; -20.0 -20.0 … 20.0 20.0], facets = [2 3 … 62 86; 1 2 … 63 88; 62 63 … 65 85], facetmarkers = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3  …  7, 10, 10, 10, 10, 10, 7, 10, 7, 8], regions = [10.27876664852878 -1.1938838093179314 -9.432278711012088 -15.151006859813176; 4.932903284952767 4.00933742966369 -4.717731819722998 -3.5021786272882673; 0.0 0.0 0.0 0.0]), (radii = [4.0 5.554882327575999 4.846487937516692], centers = [10.27876664852878 -1.1938838093179314 -9.432278711012088; 4.932903284952767 4.00933742966369 -4.717731819722998]))

The resulting mesh can be plotted in 3D provided a Makie backend is loaded.

plot_mesh(mesh)

The mesh looks good, so we can proceed with the assembly our biological model and the associated finite element matrices.

model = Model(; mesh, coeffs...)
matrices = assemble_matrices(model)
(M = sparse([1, 2, 12, 190, 191, 192, 195, 1, 2, 3  …  1145, 1150, 1318, 1323, 1324, 1768, 1772, 1782, 1821, 1824], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824], [1.3325303041367822, 0.16666666666666655, 0.16666666666666696, 0.3309413020824443, 0.3329318187350576, 0.3353238499859468, 0.6662651520683911, 0.16666666666666655, 0.9952159374982228, 0.16666666666666682  …  2.670540222315831, 3.3953556696452445, 1.612635361912306, 2.9084018282843815, 1.488906763332342, 2.135633032553417, 2.468178934200736, 2.7650446245303173, 2.1515222503620994, 20.608948102657422], 1824, 1824), S = sparse([1, 2, 12, 190, 191, 192, 195, 1, 2, 3  …  1145, 1150, 1318, 1323, 1324, 1768, 1772, 1782, 1821, 1824], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824], [0.006346996905349302, -0.001977075047162113, -0.0012664657614322714, 0.0010338376704796385, -0.002492918837158337, -0.0004164220941403156, -0.0012279528359359026, -0.001977075047162113, 0.006988755547910822, -0.001925260523849295  …  -0.0014067398416301178, -0.0015334181696860757, -0.0029915845959078945, -0.007377062330059798, 0.0019523830483469686, -0.0029824290085358656, -0.006122695920547249, -0.0003349779169020211, -0.0015176138930550226, 0.03059436456985027], 1824, 1824), R = sparse(Int64[], Int64[], Float64[], 1824, 1824), Mx = SparseArrays.SparseMatrixCSC{Float64, Int64}[sparse([1, 2, 12, 190, 191, 192, 195, 1, 2, 3  …  1145, 1150, 1318, 1323, 1324, 1768, 1772, 1782, 1821, 1824], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824], [19.11782469042412, 2.4315511144888333, 2.3090781458085727, 4.817320599469516, 4.792182159037534, 4.687881386917625, 9.148546520397721, 2.4315511144888333, 14.448326688036559, 2.377954315993194  …  10.835120767317001, 20.585324462159416, 11.206866010760761, 10.83063544590817, 9.898208990797107, 3.7215582199460324, 9.24950870139131, 16.445344590012972, 2.8820119886971813, 82.40474566171758], 1824, 1824), sparse([1, 2, 12, 190, 191, 192, 195, 1, 2, 3  …  1145, 1150, 1318, 1323, 1324, 1768, 1772, 1782, 1821, 1824], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824], [-0.5238461789627057, 0.08809193431713092, -0.22183063570571326, 0.1801774333145023, -0.07586995498830093, -0.3415365863268203, -0.09194399930883262, 0.08809193431713092, 1.446710561093754, 0.36040626920666974  …  -7.766840671243365, -11.826034216416915, -7.2548123002154785, -13.604974041151529, -6.642380978030072, -8.20066419191971, -7.120506400629633, -9.083852490187384, -11.293568690947072, -91.53780159658153], 1824, 1824), sparse([1, 2, 12, 190, 191, 192, 195, 1, 2, 3  …  1145, 1150, 1318, 1323, 1324, 1768, 1772, 1782, 1821, 1824], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824], [-25.817941940399432, -3.2638888888888866, -3.263888888888895, -6.274593858490276, -6.242471601282329, -6.356766631680946, -12.908970970199716, -3.2638888888888866, -19.35274991316038, -3.263888888888892  …  -42.11702453218053, -52.25326282429954, -26.27097249339122, -43.172832032195394, -21.47194304168049, -36.984529280208314, -42.99524947260839, -47.27191317004768, -35.26826469011216, -344.4675572255478], 1824, 1824)], Q = sparse([1, 2, 12, 190, 191, 192, 727, 728, 738, 1788  …  192, 727, 737, 738, 1167, 1171, 1173, 1787, 1790, 1792], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1  …  1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792, 1792], [0.00017356674032594226, 2.1619686615169436e-5, 2.1752261921656375e-5, 4.3190057830009714e-5, 4.341142162614532e-5, 4.3593312332961416e-5, -0.00017356674032594226, -2.1619686615169436e-5, -2.1752261921656375e-5, -4.3190057830009714e-5  …  -0.000350737092314327, 4.3593312332961416e-5, 4.408887426484085e-5, 4.3902953741119305e-5, 4.4082861744488555e-5, 4.3603497814872674e-5, 4.383546592103628e-5, 4.390578196160991e-5, 4.3724344533398e-5, 0.000350737092314327], 1824, 1824), M_cmpts = Any[sparse([1, 2, 12, 190, 191, 192, 195, 1, 2, 3  …  161, 162, 163, 164, 165, 166, 167, 168, 194, 198], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  198, 198, 198, 198, 198, 198, 198, 198, 198, 198], [1.3325303041367822, 0.16666666666666655, 0.16666666666666696, 0.3309413020824443, 0.3329318187350576, 0.3353238499859468, 0.6662651520683911, 0.16666666666666655, 0.9952159374982228, 0.16666666666666682  …  0.7547365945236499, 1.232536120202826, 2.966019587718394, 2.582828728340802, 0.4004034766974629, 0.7342348779683352, 0.9179639098339009, 1.2665265473867844, 3.9999999999999996, 37.985545474462064], 198, 198), sparse([1, 2, 17, 269, 271, 272, 279, 1, 2, 3  …  266, 267, 268, 269, 270, 271, 272, 276, 279, 280], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  280, 280, 280, 280, 280, 280, 280, 280, 280, 280], [1.856669790307353, 0.23222358552789912, 0.23222358552789926, 0.466297480790817, 0.46388772409787815, 0.4620374143628595, 0.9283348951536765, 0.23222358552789912, 1.388521999781517, 0.23222358552789926  …  1.5026399029263158, 1.9648101036019774, 1.9670432323798288, 1.5006428584523546, 1.7390521894018514, 1.9656014042348289, 1.5015281820682624, 8.944656160236484, 8.820448132647824, 67.09359502099363], 280, 280), sparse([1, 2, 15, 229, 231, 232, 248, 1, 2, 3  …  233, 234, 235, 236, 237, 238, 239, 240, 244, 248], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  248, 248, 248, 248, 248, 248, 248, 248, 248, 248], [1.5913095887190005, 0.19903357091627982, 0.19903357091627996, 0.39990324888555523, 0.3975876525269405, 0.39575154547394503, 0.7956547943595003, 0.19903357091627982, 1.1895702327804494, 0.19903357091627982  …  1.5915259938517545, 1.5839633254194139, 1.591443329928485, 1.5848577906725785, 1.5907025817551501, 1.5862328712407718, 1.5878508032015364, 1.5894318314204066, 7.463758909360495, 26.816670996585767], 248, 248), sparse([1, 2, 12, 53, 1062, 1064, 1066, 1068, 1, 2  …  419, 424, 592, 597, 598, 1042, 1046, 1056, 1095, 1098], [1, 1, 1, 1, 1, 1, 1, 1, 2, 2  …  1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098], [0.9995984854017231, 0.17204447289647445, 0.16108810313772065, 0.16666666666666652, 0.17204447289647445, 0.16666666666666646, 0.16108810313772062, 0.49979924270086157, 0.17204447289647445, 2.321373177078888  …  2.670540222315831, 3.3953556696452445, 1.612635361912306, 2.9084018282843815, 1.488906763332342, 2.135633032553417, 2.468178934200736, 2.7650446245303173, 2.1515222503620994, 20.608948102657422], 1098, 1098)], S_cmpts = Any[sparse([1, 2, 12, 190, 191, 192, 195, 1, 2, 3  …  161, 162, 163, 164, 165, 166, 167, 168, 194, 198], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  198, 198, 198, 198, 198, 198, 198, 198, 198, 198], [0.006346996905349302, -0.001977075047162113, -0.0012664657614322714, 0.0010338376704796385, -0.002492918837158337, -0.0004164220941403156, -0.0012279528359359026, -0.001977075047162113, 0.006988755547910822, -0.001925260523849295  …  0.0017495754748501349, -0.0007469995388923757, -0.004603240360876724, -0.004645195832269418, 0.002520491675485374, 0.0007315803964535931, 0.0007739644902694654, -0.0005355655805505135, -0.004340678201397818, 0.04860733979632886], 198, 198), sparse([1, 2, 17, 269, 271, 272, 279, 1, 2, 3  …  266, 267, 268, 269, 270, 271, 272, 276, 279, 280], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  280, 280, 280, 280, 280, 280, 280, 280, 280, 280], [0.00804173575255135, -0.0023778856978062665, -0.002057433198595067, -0.00013552793005669348, -0.0031809922333407206, 0.0005542470420892754, -0.0008441437348418784, -0.0023778856978062665, 0.008141834554975774, -0.002447425349101389  …  0.00025261292866535364, -0.0003733555716873339, -0.0003348683808151821, 0.00032045889182093576, 3.283365778210914e-5, -0.0002818141338107674, 0.0003725996480014941, -0.008457233992183353, -0.00837254901151355, 0.05139591384927838], 280, 280), sparse([1, 2, 15, 229, 231, 232, 248, 1, 2, 3  …  233, 234, 235, 236, 237, 238, 239, 240, 244, 248], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  248, 248, 248, 248, 248, 248, 248, 248, 248, 248], [0.007623699661914772, -0.0017121457057828649, -0.001932770481331576, 0.0003414295743444949, -0.003021449198091399, -0.00011132791627018505, -0.0011874359347832418, -0.0017121457057828649, 0.006687998426107217, -0.0017344285103734613  …  -0.0003979889800367365, -0.0007135636309145903, -0.0006307732611122894, -0.0009346644872916034, -0.0008676877801289255, -0.0010894313015867045, -0.001133326763902845, -0.001051885310977223, -0.0043853320925054656, 0.02344190991931171], 248, 248), sparse([1, 2, 12, 53, 1062, 1064, 1066, 1068, 1, 2  …  419, 424, 592, 597, 598, 1042, 1046, 1056, 1095, 1098], [1, 1, 1, 1, 1, 1, 1, 1, 2, 2  …  1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098], [0.010242327857958476, -0.003355306710475011, -0.0033943189510243707, -0.0021682054572781098, 0.0013278427244182197, -0.0009468765864350765, 0.0008371884826219335, -0.0025426513597860624, -0.003355306710475011, 0.013296522866762226  …  -0.0014067398416301178, -0.0015334181696860757, -0.0029915845959078945, -0.007377062330059798, 0.0019523830483469686, -0.0029824290085358656, -0.006122695920547249, -0.0003349779169020211, -0.0015176138930550226, 0.03059436456985027], 1098, 1098)], Mx_cmpts = Vector{Any}[[sparse([1, 2, 12, 190, 191, 192, 195, 1, 2, 3  …  161, 162, 163, 164, 165, 166, 167, 168, 194, 198], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  198, 198, 198, 198, 198, 198, 198, 198, 198, 198], [19.11782469042412, 2.4315511144888333, 2.3090781458085727, 4.817320599469516, 4.792182159037534, 4.687881386917625, 9.148546520397721, 2.4315511144888333, 14.448326688036559, 2.377954315993194  …  7.007419414814614, 12.553223682350703, 32.10685287663737, 28.747533276483406, 4.825369118793366, 9.367994258122518, 11.738111927021297, 15.948581427710725, 43.95184979899075, 410.53266455483634], 198, 198), sparse([1, 2, 17, 269, 271, 272, 279, 1, 2, 3  …  266, 267, 268, 269, 270, 271, 272, 276, 279, 280], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  280, 280, 280, 280, 280, 280, 280, 280, 280, 280], [8.533169268326766, 1.1349813603772396, 0.963766866555322, 1.9727597261201197, 2.132692793055948, 2.2220547691058554, 3.472542341888884, 1.1349813603772396, 6.841727009077427, 1.1256256092444106  …  2.1192932804716764, 3.210698636344423, 4.681001878260988, 3.6559670376193596, 5.246214895335581, 6.094992883665842, 4.7390224555183496, -2.0873031022928594, 1.8746404429431225, -0.4401188362468291], 280, 280), sparse([1, 2, 15, 229, 231, 232, 248, 1, 2, 3  …  233, 234, 235, 236, 237, 238, 239, 240, 244, 248], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  248, 248, 248, 248, 248, 248, 248, 248, 248, 248], [-10.901057170477387, -1.3127406084861089, -1.4568951306035158, -2.8700730572313238, -2.6976942568995215, -2.615457723015599, -6.044295392108538, -1.3127406084861089, -7.828137790057244, -1.3383645043011105  …  -20.751341182493345, -12.832742466604351, -20.815415635318733, -13.916190619145512, -20.15487840120918, -15.470279189236418, -17.227818064757, -18.885241144434886, -77.97690231739713, -281.2264624305779], 248, 248), sparse([1, 2, 12, 53, 1062, 1064, 1066, 1068, 1, 2  …  419, 424, 592, 597, 598, 1042, 1046, 1056, 1095, 1098], [1, 1, 1, 1, 1, 1, 1, 1, 2, 2  …  1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098], [15.395721402791153, 2.6936585388704195, 2.4239220604158946, 2.6556980158027166, 2.66512340554267, 2.5548917274920298, 2.4029871772534968, 7.856830806286128, 2.6936585388704195, 36.72042994086794  …  10.835120767317001, 20.585324462159416, 11.206866010760761, 10.83063544590817, 9.898208990797107, 3.7215582199460324, 9.24950870139131, 16.445344590012972, 2.8820119886971813, 82.40474566171758], 1098, 1098)], [sparse([1, 2, 12, 190, 191, 192, 195, 1, 2, 3  …  161, 162, 163, 164, 165, 166, 167, 168, 194, 198], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  198, 198, 198, 198, 198, 198, 198, 198, 198, 198], [-0.5238461789627057, 0.08809193431713092, -0.22183063570571326, 0.1801774333145023, -0.07586995498830093, -0.3415365863268203, -0.09194399930883262, 0.08809193431713092, 1.446710561093754, 0.36040626920666974  …  4.644070572409429, 2.3271125075379713, 16.150474264924107, 8.327024401521001, 2.4944674701569705, 1.9452492864944464, 4.837896151303015, 5.295350347824675, 12.097611172671005, 137.30184703861548], 198, 198), sparse([1, 2, 17, 269, 271, 272, 279, 1, 2, 3  …  266, 267, 268, 269, 270, 271, 272, 276, 279, 280], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  280, 280, 280, 280, 280, 280, 280, 280, 280, 280], [4.673265681138138, 0.8046468253320737, 0.37138194637761246, 0.8395230019003259, 1.1923575908210409, 1.5566291725349846, 2.6655359271269883, 0.8046468253320737, 6.066322520795689, 1.1924876435629637  …  10.410417948199248, 2.8401616897023176, 12.581329157356825, 3.376903059462519, 9.268427358869912, 6.237338737421015, 6.44937007037304, 37.48480347551342, 37.04718770163679, 281.8955624245004], 280, 280), sparse([1, 2, 15, 229, 231, 232, 248, 1, 2, 3  …  233, 234, 235, 236, 237, 238, 239, 240, 244, 248], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  248, 248, 248, 248, 248, 248, 248, 248, 248, 248], [-3.6669842844513165, -0.26303568805926875, -0.6278242651343988, -1.2391640017779517, -0.9516668917860182, -0.6162627989952668, -1.5875458779332023, -0.26303568805926875, -0.5511170388513328, 0.06259752452119742  …  -2.783455814084385, 0.09707940339877752, -1.0356446298192223, 1.467820574423612, 0.5874049073440297, 2.2839519628409204, 2.403424913716571, 1.8038237764398675, -9.878914413531936, -26.68098100225745], 248, 248), sparse([1, 2, 12, 53, 1062, 1064, 1066, 1068, 1, 2  …  419, 424, 592, 597, 598, 1042, 1046, 1056, 1095, 1098], [1, 1, 1, 1, 1, 1, 1, 1, 2, 2  …  1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098], [-0.7299485773910855, -0.000665974639365581, -0.25101909725502464, -0.181337832009083, 0.05205478126986286, -0.07804341389543414, -0.20254309843983243, -0.35966900560849335, -0.000665974639365581, 3.6740370963571367  …  -7.766840671243365, -11.826034216416915, -7.2548123002154785, -13.604974041151529, -6.642380978030072, -8.20066419191971, -7.120506400629633, -9.083852490187384, -11.293568690947072, -91.53780159658153], 1098, 1098)], [sparse([1, 2, 12, 190, 191, 192, 195, 1, 2, 3  …  161, 162, 163, 164, 165, 166, 167, 168, 194, 198], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  198, 198, 198, 198, 198, 198, 198, 198, 198, 198], [-25.817941940399432, -3.2638888888888866, -3.263888888888895, -6.274593858490276, -6.242471601282329, -6.356766631680946, -12.908970970199716, -3.2638888888888866, -19.35274991316038, -3.263888888888892  …  -3.1095397180724413, -5.038137845474553, -11.539612094814075, -9.824286368086675, -1.6404364453611868, -3.1705706964164184, -3.8600101889903584, -4.8884386549898435, -36.666666666666664, -242.8117173890429], 198, 198), sparse([1, 2, 17, 269, 271, 272, 279, 1, 2, 3  …  266, 267, 268, 269, 270, 271, 272, 276, 279, 280], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  280, 280, 280, 280, 280, 280, 280, 280, 280, 280], [-35.973210290104106, -4.547711883254691, -4.547711883254694, -8.839837592131111, -8.697894826835213, -8.759961346606907, -17.986605145052046, -4.547711883254691, -27.000377638358913, -4.547711883254694  …  -24.990190821574572, -32.21496266548419, -32.25227287587231, -24.95662356094601, -28.688661125109448, -32.228183576737365, -24.971505677608917, -106.33505107570753, -152.63587983919805, -982.6065894965417], 280, 280), sparse([1, 2, 15, 229, 231, 232, 248, 1, 2, 3  …  233, 234, 235, 236, 237, 238, 239, 240, 244, 248], [1, 1, 1, 1, 1, 1, 1, 2, 2, 2  …  248, 248, 248, 248, 248, 248, 248, 248, 248, 248], [-30.831823068641313, -3.897740763777146, -3.8977407637771493, -7.58111657115261, -7.454768484880133, -7.503272132184919, -15.415911534320657, -3.897740763777146, -23.13181874648575, -3.897740763777146  …  -28.883359212372863, -28.74943695888349, -28.88189537206496, -28.765276447741627, -28.868777956495492, -28.78962683280338, -28.81827771127525, -28.84627508598441, -127.50588136824177, -500.9246160098465], 248, 248), sparse([1, 2, 12, 53, 1062, 1064, 1066, 1068, 1, 2  …  419, 424, 592, 597, 598, 1042, 1046, 1056, 1095, 1098], [1, 1, 1, 1, 1, 1, 1, 1, 2, 2  …  1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098, 1098], [-19.15897097019969, -3.3322412860713153, -3.1222441990285343, -3.263888888888885, -3.1911116445866736, -3.055555555555552, -2.9856797116100395, -9.371235800641154, -3.3322412860713153, -44.56243033845646  …  -42.11702453218053, -52.25326282429954, -26.27097249339122, -43.172832032195394, -21.47194304168049, -36.984529280208314, -42.99524947260839, -47.27191317004768, -35.26826469011216, -344.4675572255478], 1098, 1098)]], G = Any[[3.1090393294905123 -1.1992888095955179 -2.3443790760237686; 2.4323069210533927 0.5864083237345679 -2.7334364461705283; … ; 0.0 0.0 0.0; 0.0 0.0 0.0], [3.1193845762270946 -1.2032794116203933 -3.4528414016351734; 2.5035289780877705 0.13934379968952898 -3.4910072151694207; … ; 0.0 0.0 -31.582407631794318; 0.0 0.0 0.0], [3.0643379264105572 -1.1820455756555337 -3.489184425021361; 2.4480388841794634 0.27885297738705117 -3.155548435753369; … ; 0.0 0.0 0.0; 0.0 0.0 -23.884028509953588], [3.1090393294905123 -1.1992888095955179 -1.011045742690433; 2.4323069210533927 0.5864083237345679 -3.400103112837189; … ; 5.874081955536858 -11.889833332045157 0.7682874663343249; 3.52827637147994 -20.04284146264382 1.3974288381186803]], volumes = [1918.940233608673, 3787.456852888135, 2864.169516788822, 10699.297136081648])

The Bloch-Torrey PDE takes a magnetic field gradient pulse sequence as an input. Here we consider a ScalarGradient with a PGSE time profile.

dir = [1.0, 0.0, 0.0]
profile = PGSE(2000.0, 6000.0)
b = 1000
g = √(b / int_F²(profile)) / coeffs.γ
gradient = ScalarGradient(dir, profile, g)
ScalarGradient{Float64, PGSE{Float64}}([1.0, 0.0, 0.0], PGSE{Float64}(2000.0, 6000.0), 0.8093302043119762)

SpinDoctor provides a solve function, which has the same base signature for all diffusion MRI problems. The BTPDE is one such problem. They generally take a gradient sequence as an input.

btpde = BTPDE(; model, matrices)
ξ = solve(btpde, gradient)
1824-element Vector{ComplexF64}:
 0.42151898276843097 + 0.4225807888202752im
 0.40258366336102885 + 0.45706295788188617im
 0.45577765300614004 + 0.3827143874574771im
  0.5328395420617785 + 0.21163345238394543im
  0.5464390534024666 - 0.017901451694179997im
 0.49007843969439085 - 0.22617349671501216im
 0.41760247883241997 - 0.3524233969269779im
 0.39627074239026594 - 0.37388243410830074im
  0.4446450105061987 - 0.3014344727022567im
  0.5134150228736285 - 0.13921411958240953im
                     ⋮
 0.13786722927088685 - 0.031723613731392014im
  0.2336829373189278 - 0.19591894192687145im
 0.18640987459140992 - 0.04313466408415677im
 0.15552549398558724 - 0.02588167938464815im
 0.11445698256616671 + 0.010184498969924334im
 0.15689950304035777 + 0.07644876228879041im
  0.2539180429885351 + 0.19837903125473585im
 0.18512946984860332 + 0.06023247406419295im
 0.12048062054335919 - 0.018738097056034738im

Here, ξ is a vector containing the complex-valued magnetization at all degrees of freedom at the echo time TE. We may compute the resulting signal as follows:

compute_signal(matrices.M, ξ)
6268.55354366481 - 0.4912644720153221im

The global mass matrix M is used to compute the integral. We may however be interested in the compartment-wise signals. This requires splitting the magnetization field into the respective compartments. The compartment mass matrices are also available.

ξ_cmpts = split_field(mesh, ξ)
compute_signal.(matrices.M_cmpts, ξ_cmpts)
4-element Vector{ComplexF64}:
  952.1587226283762 + 31.195441404487877im
 1243.7482992899832 - 8.093519658681421im
 1166.3676621178745 - 7.144096023692393im
 2906.2788596285764 - 16.44909019412938im

The final magnetization can be visualized using the plot_field function.

plot_field(mesh, ξ)

In this example, we have computed the complex transverse water proton magnetization field using the finite element method. The measured diffusion MRI signal is the integral of this field, and other quantities of interest, such as the apparent diffusion coefficient (ADC), or the effective diffusion tensor, may easily be obtained from this reference field. Directly solving the BTPDE is thus considered to be the "gold standard" for computing these quantities, as arbitrary precision may be obtained.

However, this is also often the most computationally expensive approach. In the following examples, we will consider some other specialized methods provided by SpinDoctor, each having their own domains of validity, use cases, and computational footprints.


This page was generated using Literate.jl.