◆ FORGE Suite
GitHubMechanical Neuroimaging Lab · Univ. of Delaware
Skip to content

Preprocessing

Tools for generating finite element meshes from MRI data, reading MRI displacement data from multiple scanner formats, and processing DTI fiber directions.

MRI Data

Sentinel.MREData Type
julia
MREData

Container for MRE displacement data produced by all three reader functions.

Fields

  • Ur::Array{Float64}: Real part of displacement. 4D [nx, ny, nz, 3] or 5D [nx, ny, nz, 3, nsets] for multi-set WashU data.

  • Ui::Array{Float64}: Imaginary part of displacement (same shape as Ur).

  • anatomical::Array{Float64, 3}: Anatomical/magnitude image [nx, ny, nz].

  • mask::BitArray{3}: Binary mask [nx, ny, nz].

  • voxel_size::NTuple{3,Float64}: Voxel sizes in mm (x, y, z).

  • freq_hz::Float64: MRE driving frequency in Hz.

  • motion2image::Matrix{Float64}: 3×3 direction transform matrix.

  • rh_coord::Bool: Right-handed coordinate system flag.

source

MRI Readers

Sentinel.read_mre_siemens Function
julia
read_mre_siemens(phase_dirs::Vector{String}; fft_bin::Int=2,
                  freq_hz::Float64=NaN) -> MREData

Read Siemens MRE DICOM phase images from three directories (one per motion- encoding direction).

Arguments

  • phase_dirs: Vector of 3 directory paths, each containing DICOM .IMA or .dcm files for one motion-encoding direction.

  • fft_bin: FFT bin to extract (1=DC, 2=fundamental harmonic). Default: 2.

  • freq_hz: MRE driving frequency in Hz. If NaN, attempts to read from DICOM.

Ports SiemensProcessing.m.

source
Sentinel.read_mre_washu Function
julia
read_mre_washu(matfile::String) -> MREData
read_mre_washu(matfiles::Vector{String}) -> MREData

Read WashU-format MRE data from one or more .mat files.

Each file must contain:

  • PCWU_BMR: 5D phase-contrast array [n1, n2, n3, nph, ndir]

  • mask: binary 3D mask

  • MAGmean: mean magnitude image

  • voxsize: scalar or 3-element voxel size in mm

  • PC2micron: phase-contrast to micron conversion factor

  • ActFreq or Freq: excitation frequency in Hz

Multiple files produce 5D output [nx, ny, nz, 3, nsets].

Ports WashU_to_NLI_convert.m.

source
Sentinel.read_mre_uiuc Function
julia
read_mre_uiuc(matfile::String) -> MREData

Read UIUC-format MRE data from a .mat file.

The file must contain:

  • Xmotion, Ymotion, Zmotion: complex 3D displacement arrays [nx, ny, nz]

  • t2stack: anatomical T2 image [nx, ny, nz]

  • One of new_mask, eroded_mask, or mask: binary mask [nx, ny, nz]

  • mreParams: struct with fields FOVx, FOVy, FOVz, nx, ny, nz, freq

Ports UIUC_data_convert.m and MRE_MotionData_convert.m.

source

Hex Mesh Generation

Generate hex27 finite element meshes from MRI displacement data with configurable resolution strategies.

Sentinel.HexMeshConfig Type
julia
HexMeshConfig

Configuration for hex27 mesh generation from MRI data.

Fields

  • mesh_strategy::Int: 1=one node per voxel, 2=target wavelength, 3=target resolution

  • target_resolution::NTuple{3,Float64}: Target resolution in meters (strategy 3)

  • nodes_per_wavelength::Int: Target nodes per wavelength (strategy 2)

  • mu_estimate::Float64: Estimated shear modulus in Pa (strategy 2)

  • rho_estimate::Float64: Estimated density in kg/m³

  • disp_scale::Bool: Whether to scale displacements

  • disp_scalar::Float64: Target average displacement amplitude

  • buffer_size::NTuple{3,Int}: Buffer voxels around mask, must be even

  • spline_bc_type::Int: Spline boundary condition: 1=natural, 2=clamped

source
Sentinel.HexMeshResult Type
julia
HexMeshResult

Result of hex27 mesh generation from MRI data.

Fields

  • grid: Ferrite Grid (Hexahedron cells, 8 corner nodes per cell)

  • full_connectivity::Matrix{Int}: (ne, 27) Ferrite-ordered connectivity

  • node_coords::Matrix{Float64}: (nn, 3) node coordinates in meters

  • disp_real::Matrix{Float64}: (nn, 3) real displacement (transformed)

  • disp_imag::Matrix{Float64}: (nn, 3) imaginary displacement (transformed)

  • boundary_nodes::Vector{Int}: Sorted boundary node IDs

  • mesh_resolution::NTuple{3,Float64}: Actual mesh resolution in meters

  • anatomical_nodes::Vector{Float64}: (nn,) magnitude image at nodes

  • region_nodes::Vector{Int}: (nn,) region assignment (0=unassigned)

  • disp_scale_factor::Float64: Displacement scaling factor applied

  • nn::Int: Total nodes

  • ne::Int: Total elements

source
Sentinel.generate_hex_mesh Function
julia
generate_hex_mesh(mre::MREData, config::HexMeshConfig=HexMeshConfig();
                  regions=nothing) -> HexMeshResult

Generate a structured Hex27 finite element mesh from MRI displacement data.

Arguments

  • mre::MREData: MRE displacement data with mask, voxel sizes, etc.

  • config::HexMeshConfig: Mesh generation configuration

  • regions: Optional 3D array of region assignments (same size as mask)

Strategies

  1. One node per voxel (no interpolation)

  2. Target nodes per wavelength (spline interpolation)

  3. Target resolution (spline interpolation)

source
Sentinel.write_hex_mesh_files Function
julia
write_hex_mesh_files(result::HexMeshResult, stem::String)

Write hex mesh result to legacy NLI format files.

Writes stem.nod, stem.elm, stem.dsp, stem.bnd.

source

DTI Fiber Processing

Process diffusion tensor imaging data and interpolate fiber directions to FEM mesh elements for transverse isotropic models (5, 6, 7).

Sentinel.DTIData Type
julia
DTIData

Container for processed DTI data.

Fields

  • V1::Array{Float64, 4}: Principal eigenvector field [nx, ny, nz, 3].

  • FA::Array{Float64, 3}: Fractional anisotropy map [nx, ny, nz].

source
Sentinel.process_dti Function
julia
process_dti(dti_matfile::String, mre_size::NTuple{3,Int};
            dti_offset::NTuple{3,Int}=(1,1,1)) -> DTIData

Process DTI data from a .mat file and crop to MRE image space.

Arguments

  • dti_matfile: Path to .mat file containing evec (eigenvector array, [DTI_nx, DTI_ny, DTI_nz, 3]) and FA (fractional anisotropy, [DTI_nx, DTI_ny, DTI_nz]).

  • mre_size: Target output size (nx, ny, nz) matching the MRE data grid.

  • dti_offset: 1-based offset of MRE grid origin in DTI voxel space. Default (1,1,1) means the DTI and MRE grids are aligned.

Returns

DTIData with V1 and FA cropped to the MRE grid.

Ports WashU_DTI_Process.m.

source
Sentinel.interpolate_fiber_directions Function
julia
interpolate_fiber_directions(dti::DTIData, grid,
                             voxel_size::NTuple{3,Float64};
                             origin::NTuple{3,Float64}=(0.0, 0.0, 0.0)
                             ) -> Vector{Vec{3,Float64}}

Map voxel-based DTI fiber directions to per-element fiber vectors for FEM.

For each element in grid, computes the element centroid, maps it to the nearest DTI voxel, and extracts the (unit-normalized) principal eigenvector.

Arguments

  • dti: Processed DTI data with V1 field [nx, ny, nz, 3].

  • grid: Ferrite grid.

  • voxel_size: DTI voxel dimensions in physical units (dx, dy, dz).

  • origin: Physical coordinates of the first DTI voxel center.

Returns

Vector of Vec{3,Float64} fiber directions, one per element.

source