API Reference
Gradients
These functions deal with gradient pulse sequences.
SpinDoctor.GeneralGradient
— TypeGeneralGradient(g⃗, TE)
General gradient sequence $\vec{g}(t) \in \mathbb{R}^3$. The direction and amplitude may vary in time.
SpinDoctor.ScalarGradient
— TypeScalarGradient(dir, profile, amplitude)
Gradient sequence with amplitude amplitude
, normal direction dir
and scalar time profile profile
.
The direction is constant, while the amplitude is controlled by the time profile.
The direction is normalized upon construction.
SpinDoctor.PGSE
— Typef = PGSE(δ, Δ)
Pulsed Gradient Spin Echo sequence with pulse duration δ
and time between pulses Δ-δ
.
SpinDoctor.DoublePGSE
— Typef = DoublePGSE(δ, Δ)
Double Pulsed Gradient Spin Echo sequence with four pulses of duration δ
, separated by pauses of duration Δ-δ
, 0
, and Δ-δ
repsectively.
SpinDoctor.CosOGSE
— Typef = CosOGSE(δ, Δ, nperiod)
Oscillating Gradient Spin Echo sequence with two cos-pulses of duration δ
separated by a pause of duration Δ-δ
for nperiod
periods per pulse.
SpinDoctor.SinOGSE
— Typef = SinOGSE(δ, Δ, nperiod)
Oscillating Gradient Spin Echo sequence with two sin-pulses of duration δ
separated by a pause of duration Δ-δ
for nperiod
periods per pulse.
SpinDoctor.integral
— Functionintegral(f, t = echotime(f))
Integral of time profile f
between 0
and t
. Unless specified, the echotime is used as the upper integral limit.
For the PGSE
, SinOGSE
, CosOGSE
and DoublePGSE
sequences, analytical expressions are available. Otherwise a numerical integral is computed.
SpinDoctor.int_F²
— Functionint_F²(f)
Compute the time profile contribution to the $b$-value given the time profile f
. The $b$-value is given by
b = γ^2 * g^2 * int_F²(f)
where γ
is the gyromagnetic ratio of the water proton and g
is the gradient amplitude.
SpinDoctor.intervals
— Functionintervals(f)
Get characteristic intervals of the time profile f
.
SpinDoctor.isconstant
— Functionisconstant(profile)
Return true
if the time profile profile
is intervalwise constant.
SpinDoctor.echotime
— Functionechotime(f::TimeProfile)
Get echo time $TE$ of the time profile f
, which is the end of the last characteristic interval.
echotime(grad::AbstractGradient)
Get echo time $TE$ of gradient
.
Geometry
SpinDoctor.assemble_matrices
— Functionassemble_matrices(model)
Assemble finite element matrices.
SpinDoctor.split_mesh
— Functionsplit_mesh(mesh_all)
Split global mesh into compartments.
SpinDoctor.split_field
— Functionsplit_field(mesh, ξ)
Split the field ξ
into a vector containing a view
of each compartment.
SpinDoctor.get_cmpt_volumes
— Functionget_cmpt_volumes(mesh)
Get compartment volumes.
SpinDoctor.Model
— TypeModel(; mesh, ρ, D, T₂, κ, γ)
Finite element discretized biological model with initial spin densities ρ
, diffusion tensors D
, T₂-relaxation times T₂
, wall permeabilities κ
, and gyromacnetic ratio γ
. The vectors ρ
, D
, T₂
, are of length ncompartment
, while κ
is of length nboundary
.
SpinDoctor.initial_conditions
— Functioninitial_conditions(model)
Get initial conditions at all degrees of freedom.
Postprocessing
SpinDoctor.savefield
— Functionsavefield(mesh, ξ, filename::String; fieldname = "Magnetization")
Save field ξ
to a VTK file. It may then be visualized in Paraview.
SpinDoctor.compute_adc_sta
— Functioncompute_adc_sta(model)
Compute the ADC for each compartment in the short diffusion time regime.
SpinDoctor.fit_adc
— Functionfit_adc(bvalues, signals)
Fit the apparent diffusion coefficient (ADC) using a polynomial logfit of the normalized signals signals
against the b-values bvalues
.
SpinDoctor.fit_tensors
— Functionfit_tensors(directions, adcs)
Fit effective diffusion tensors to directionalized ADCs. The six components of the symmetric diffusion tensors are fitted by least squares to the gradient directions and resulting ADCs.
SpinDoctor.plot_mesh
— Functionplot_mesh(femesh, compartments = 1:ncompartment)
Plot finite element mesh, with a subset of the compartments.
SpinDoctor.plot_field
— Functionplot_field(femesh, ξ)
Plot field ξ
on the finite element mesh.
Problems
SpinDoctor allows for considering a wide range of diffusion MRI problems. These can be solved for using the solve
function.
SpinDoctor.BTPDE
— TypeGeneralBTPDE(; model, matrices)
Bloch-Torrey PDE problem.
SpinDoctor.HADC
— TypeHADC(; model, matrices)
HADC problem.
SpinDoctor.Karger
— TypeKarger(; model, difftensors)
Karger problem.
SpinDoctor.Laplace
— TypeLaplace(; model, matrices, neig_max)
Laplace eigenvalue problem.
SpinDoctor.MatrixFormalism
— TypeMatrixFormalism(; model, matrices, lap_eig)
Matrix formalism problem. Given a Laplace eigendecomposition lap_eig
, this problem consists of computing the MF magnetization.
SpinDoctor.AnalyticalLaplace
— TypeAnalyticalLaplace(; ρ, r, D, W, T₂, γ, dim, eiglim, eigstep)
Analytical radial Laplace eigenvalue problem.
SpinDoctor.AnalyticalMatrixFormalism
— TypeAnalyticalMatrixFormalism(; analytical_laplace, lap_mat, volumes)
Analytical Matrix formalism problem. Given a radial Laplace eigendecomposition analytical_laplace
, this problem consists of computing the MF compartment signals.
SpinDoctor.IntervalConstantSolver
— TypeIntervalConstantSolver(; θ = 0.5, timestep)
BTPDE solver specialized on intervalwise constant ScalarGradient
s, e.g PGSE
, DoublePGSE
. Raises an error for other gradients.
SpinDoctor.solve
— Functionsolve(problem::Laplace)
Compute the Laplace eigenvalues, eigenfunctions and first order moments of products of pairs of eigenfunctions.
solve(problem::MatrixFormalism, gradient; ninterval = 500)
Solve for magnetization using Matrix Formalism.
solve(problem::AnalyticalLaplace)
Solve analytical Laplace eigenvalue problem for symmetrical geometries.
solve(problem::AnalyticalMatrixFormalism, gradient)
Compute the signal in a multilayered cylinder or sphere using an analytical matrix formalism solution.
This function is based on the following articles and corresponding code: [1] D. S. Grebenkov, NMR Survey of Reflected Brownian Motion, Rev. Mod.Phys. 79, 1077 (2007) [2] D. S. Grebenkov, Pulsed-gradient spin-echo monitoring of restricted diffusion in multilayered structures, J. Magn. Reson. 205, 181-195 (2010).
solve(
problem::GeneralBTPDE,
gradient,
odesolver = QNDF();
abstol = 1e-6,
reltol = 1e-4,
callbacks = [].
)
Solve the Bloch-Torrey partial differential equation using P1 finite elements in space and odesolver
in time.
function solve(
problem::BTPDE,
gradient::ScalarGradient,
odesolver::IntervalConstantSolver;
callbacks = [],
)
Solve the Bloch-Torrey partial differential equation using P1 finite elements in space and a theta-rule in time. This time stepping scheme requires a degree of implicitness θ
and a time step Δt
:
θ = 0.5
: Crank-Nicolson (second order)θ = 1.0
: Implicit Euler (first order)
The function only works for interval-wise constant ScalarGradient
s, and errors otherwise.
solve(problem::Karger, gradient, odesolver = MagnusGL6(); timestep)
Solve the finite pulse Karger model (FPK) using precomputed effective diffusion tensors difftensors
.
solve(problem::HADC, gradient::ScalarGradient, odesolver = QNDF();
abstol = 1e-6,
reltol = 1e-4,
)
Compute the ADC using a homogenized ADC model (HADC). This is currently only implemented for scalar gradients.
SpinDoctor.solve_multigrad
— Functionsolve_multigrad(problem, gradients, args...; kwargs...)
Solve problem
for multiple magnetic field gradients.
Matrix formalism
SpinDoctor.length2eig
— Functionlength2eig(length, D)
Convert length scale to Laplace eigenvalue.
SpinDoctor.eig2length
— Functioneig2length(λ, D)
Convert Laplace eigenvalue to length scale.
SpinDoctor.limit_lengthscale
— Functionlimit_lengthscale(lap_eig, λ_max)
Only keep modes with length scales larger than minimum
SpinDoctor.compute_mf_diffusion_tensor
— Functioncompute_mf_diffusion_tensor(mesh, M, lap_eig, gradient::ScalarGradient)
Compute effective diffusion tensors using the matrix formalism.
Utils
SpinDoctor.unitcircle
— Functionunitcircle(ndirection; half = false, normal = [0, 0, 1])
Create ndirection
directions unformly distributed on the unit circle defined by normal
.
If half
is true
, the directions lie on a half-circle instead of the whole circle.
SpinDoctor.unitsphere
— Functionunitsphere(ndirection; half = false, normal = [0, 0, 1])
Create ndirection
directions unformly distributed on the unit sphere.
If half
is true
, the points will be discributed on the hemisphere defined by normal
.
SpinDoctor.compute_signal
— Functioncompute_signal(M, ξ)
Compute signal from magnetization ξ
, using the mass matrix M
for integration.
Given a mesh mesh
and a vector of compartment mass matrices M_cmpts
, a vector of compartment signals may be obtained by compute_signal.(M_cmpts, split_field(mesh, ξ))
.
Callbacks
Callbacks are called after every time step when solving the BTPDE.
SpinDoctor.Printer
— TypePrinter(; nupdate = 1)
Print time stepping information to the console.
SpinDoctor.VTKWriter
— TypeVTKWriter(; nupdate = 1, dir = "output", filename = "solution")
Write magnetization field to a VTK file after every nupdate
timestep. The files are stored in a ParaView data collection file (PVD). The magnetization time series may be visualized in ParaView by opening the file "$dir/$filename.pvd"
. The compartments are labeled.
SpinDoctor.Plotter
— TypePlotter(; nupdate = 1)
Plot the evolution of the BTPDE during time stepping. This requires loading the GLMakie
plotting backend (]add GLMakie; using GLMakie
). The plot is updated every nupdate
time step. The resulting figure contains a plot of the time profile, total signal attenuation, and magnetization field (complex magnitude and phase shift).
Recipes
SpinDoctor comes with pre-configures recipes for creating finite element meshes of plates, cylinders, spheres, and neurons.
SpinDoctor.PlateSetup
— TypeSetup recipe for a set of stacked plates.
SpinDoctor.CylinderSetup
— TypeSetup recipe for a set of cylinders immersed in a ECS.
SpinDoctor.SphereSetup
— TypeSetup recipe for a set of spheres immersed in a ECS.
SpinDoctor.NeuronSetup
— TypeSetup recipe for a neuron, possibly wrapped in a ECS.
SpinDoctor.coefficients
— Functioncoefficients(setup; D, T₂, ρ, κ, γ)
Order coefficients compartment arrays.
SpinDoctor.analytical_coefficients
— Functionanalytical_coefficients(setup, coeffs)
Get coefficients for the analytical module.
SpinDoctor.create_geometry
— Functioncreate_geometry(setup; recreate = true)
Create cells, surfaces and finite element mesh. If recreate = false
, previous geometry will be reused.
This function does the following:
- Check geometry setup consistency
- Create or load cell configuration
- Create or load surface triangulation
- Call TetGen
- Deform domain
- Split mesh into compartments
For custom geometries with more than one compartment, call split_mesh
directly instead. This requires facet and element labels.