Obstructions to free diffusion

MCMRSimulator.jl provides several geometry representations for restricting diffusion and assigning MRI properties to tissue compartments.

Geometry representations

GeometryJulia constructorCLI or file sourceIntrinsic dimensionalityTypical use
Infinite wallsWallsmcmr geometry create walls1Parallel planes
Infinite cylindersCylindersmcmr geometry create cylinders2Repeating cylindrical fibres
Cylindrical annuliAnnulimcmr geometry create annuli2Myelinated cylindrical fibres
SpheresSpheresmcmr geometry create spheres3Spherical cells or sphere-based morphologies
Connected finite cylindersFiniteCylindersUsually loaded from SWC3Connected morphology with spherical nodes and cylindrical links
MeshesMeshPLY files or generated externally3Arbitrary closed surfaces
Bendy cylindersBendyCylindermcmr geometry create bendy-cylinder3Curved or varying-radius fibres
Liminal geometryLiminalGeometrymcmr geometry create liminal3Statistical populations of cells without explicit global packing

Cylinders and Annuli are intrinsically two-dimensional geometries. Applying a rotation embeds them in three-dimensional space. FiniteCylinders, by contrast, are three-dimensional connected structures and should not be confused with infinitely repeating Cylinders.

Loading geometry files

read_geometry is the general entry point for loading geometry files. When no format is supplied, it detects the format from the file contents rather than the filename extension.

FormatDedicated readerResult and notes
JSONread_geometry_jsonUser-defined obstruction groups
PLYload_meshA Mesh geometry
SWCread_swcFiniteCylinders by default; use swc_as_spheres=true for overlapping Spheres
CATERPillarread_caterpillarOverlapping Spheres groups from CATERPillar's whitespace-delimited output
LiminalLiminal geometryA LiminalGeometry with child geometry files

For example, the format can normally be inferred automatically:

using MCMRSimulator

geometry = read_geometry("geometry_file")

For streams, or when an explicit override is useful, pass format:

geometry = read_geometry(io; format=:swc, swc_as_spheres=true)

See the linked reader docstrings for the format-specific syntax and options.

Overlapping spheres

Set overlapping=true on Spheres when a sequence of overlapping spheres represents one continuous structure. This is the representation used by read_swc(...; swc_as_spheres=true) and read_caterpillar. It differs from a collection of independent, non-overlapping spherical obstructions: overlapping spheres are treated as permeable within their overlapping regions so that the chain does not create artificial barriers between adjacent samples.

Connected finite cylinders

FiniteCylinders represents a connected morphology using spherical endpoints and cylindrical links. read_swc constructs these links from the parent IDs in an SWC file. Use this representation when explicit node connectivity is available and cylindrical links are appropriate; use swc_as_spheres=true when the sphere samples themselves are the desired morphology representation.

Generating custom geometries

The constructors for these components all have a similar interface. Some expect certain component-specific keyword arguments (e.g., radius for Spheres and Cylinders, or the keywords regarding the myelin-induced off-resonance field produced by Cylinders or Annuli). MRI relaxation properties within the obstruction and collision parameters (stuck spins, magnetisation transfer rate & permeability) can be set using keyword arguments as described in the properties section. Finally, these constructors expect a set of keyword arguments that control their location. These arguments are identicaly across all constructors (although the expected input depends on the dimensionality of the component as listed in the table above):

  • position: Set the positions for each generated components (not used in Mesh).
  • repeats: Set the distance with which all components should be repeated.
  • rotation: Applies a single rotation to the whole system.

Components with a lower dimensionality are defined by default along the x-axis (for dimensionality of 1) or the x-y plane (for dimensionality of 2). In other words, the normal of the Walls point in the x-axis by default, while the Cylinders point in the z-axis. Shifts and repeats should only be provided in this lower-dimensional space. The rotation keyword can be used to define these components along other lines/planes (see MCMRSimulator.get_rotation).

Warning

This repeating geometry means that a spin leaving the geometry at the top of the bounding box, will next see the geometry at the bottom of the bounding box. For this to make sense any geometries going beyond the top of the bounding box should continue at the bottom of the bounding box. Future versions of MCMRSimulator will allow spins to continue in a flipped version of the geometry, which ensures that any geometries crossing the bounding box boundary are continuous (see tracking issue).

From the command line all of these keywords are available as flags, which can be seen by running:

 mcmr geometry create walls/cylinders/annuli/spheres/bendy-cylinder --help

In Julia, the easiest way to get the documentation for all keywords is to run:

?Walls/Cylinders/Annuli/Spheres/Mesh/BendyCylinder

or by following the links in the table above. For meshes use the load_mesh function to read a mesh from disk.

For example, we can create two base cylinders, which repeat infinitely by running:

using MCMRSimulator
geometry = Cylinders(radius=sqrt(0.5), position=[[0, 0], [1, 1]], repeats=[2, 2])

Plot showing two cylinders repeating ad infinitum

Alternatively, the same configuration could be produced with a single cylinder by providing a rotation.

using MCMRSimulator
rotation = [
    sqrt(0.5) sqrt(0.5) 0.
    -sqrt(0.5) sqrt(0.5) 0.
    0. 0. 1.
    ]
geometry = Cylinders(radius=sqrt(0.5), repeats=[sqrt(2), sqrt(2)], rotation=rotation)

Plot showing single cylinders repeating ad infinitum

Randomly distributed cylinders/annuli/spheres

A random set of positions and radii can be created using random_positions_radii. The user in this case sets a target density (70% in the example below) and over which length scale the configuration should repeat itself (20x20 micrometer in the example below).

(positions, outer_radii) = random_positions_radii((20, 20), 0.7, 2)

From the command line this functionality is available by running mcmr geometry create-random cylinders/annuli/spheres.

These can be used to produce randomly distributed cylinders:

geometry = Cylinders(radius=outer_radii, position=positions, repeats=(20, 20))

Illustrating configuration of random cylinders

When used as initialisation for annuli, an inner radius will also need to be computed:

geometry = Annuli(inner=0.8 .* outer_radii, outer=outer_radii, position=positions, repeats=(20, 20))

Illustrating configuration of random annuli