Getting Started
Installation
Sentinel.jl is not yet registered in the Julia General registry. Install directly from the repository:
using Pkg
Pkg.add(url="https://github.com/acerjanic/sentinel")Requirements: Julia 1.10+, Ferrite.jl 1.3.0 (installed automatically).
Optional Dependencies
# MUMPS solver (recommended for large problems)
Pkg.add("MUMPS")
# GPU acceleration (Apple Silicon)
Pkg.add("Metal")
# GPU acceleration (NVIDIA)
Pkg.add("CUDA")
Pkg.add("CUDSS")
# AppleAccelerate (macOS — loaded automatically, ~13% faster sparse solves)
Pkg.add("AppleAccelerate")AppleAccelerate
On macOS, Sentinel automatically loads AppleAccelerate if available, switching the BLAS/LAPACK backend to Apple's Accelerate framework. This gives ~13% faster sparse LU solves on Apple Silicon.
Tutorial 1: Forward Problem
This tutorial solves a forward problem on a simple hex27 mesh with isotropic incompressible material (Model 1).
using Sentinel, Ferrite
# 1. Create a hex27 mesh (4x4x4 elements)
grid = generate_grid(Hexahedron, (4, 4, 4))
dh = setup_hex27_dofhandler(grid)
# 2. Set up cell values for integration
ip_scalar = Lagrange{RefHexahedron, 2}()
ip_press = Lagrange{RefHexahedron, 1}()
qr = QuadratureRule{RefHexahedron}(3)
cv_disp = CellValues(qr, ip_scalar)
cv_press = CellValues(qr, ip_press)
# 3. Define material properties
model = IsotropicIncompressible()
omega = 2pi * 60.0 # 60 Hz excitation frequency
rho = 1000.0 # density [kg/m^3]
# Create Gauss-point material with uniform properties
ne = getncells(grid)
ngp = 27 # 3x3x3 Gauss points
mu_val = complex(3000.0, -300.0) # shear modulus [Pa]
kappa_val = complex(2.0e9, 0.0) # bulk modulus [Pa]
props = GaussPointMaterial(
mu = fill(mu_val, ne, ngp),
kappa = fill(kappa_val, ne, ngp),
rho = fill(rho, ne, ngp),
ρ = fill(rho, ne, ngp)
)
# 4. Allocate and assemble
K = allocate_stiffness(dh, model)
assemble_stiffness!(K, dh, cv_disp, cv_press, model, props, omega)
# 5. Apply boundary conditions and solve
f = zeros(ComplexF64, size(K, 1))
# ... set up BCs and RHS, then:
# forward_solve!(disp, K, f, model, dispset; solver=DirectSolver())Tutorial 2: Runfile Workflow
The most common workflow uses Fortran-compatible runfiles (.dat format):
using Sentinel
# Parse a .dat runfile (same format as Fortran MRE-Zone)
config = parse_runfile("brain_mre.dat")
# Load all files and set up the complete problem
setup = setup_forward_problem(config, "/path/to/data/")
# Access the loaded components
grid = setup.grid
dh = setup.dh
model = setup.model
material = setup.material
bcs = setup.bcs
K = setup.KThe setup_forward_problem function reads all referenced files (.nod, .elm, .dsp, .mtr, .bnd, .bcs) and constructs the complete problem including the DOF handler, material mesh interpolation, and pre-assembled stiffness matrix.
Tutorial 3: Inverse Problem
Set up and run an inverse reconstruction using conjugate gradient with Tikhonov regularization:
using Sentinel
# ... (load data via runfile or manual setup) ...
# Set up regularization
tikhonov = TikhonovReg(1, 1e-4, 1e-4, material) # prop 1, weights, reference from material
# Build the forward problem context
ctx = ForwardProblemContext(
grid=grid, dh=dh, cv_disp=cv_disp, cv_press=cv_press,
model=model, bcs=bcs, meas=meas, omega=omega, rho=rho,
regularizations=[tikhonov], solver=DirectSolver(),
numdispsets=1
)
# Initialize gradient structure
grad = MaterialGradient()
init_gradient!(grad, material)
# Run CG optimizer
result_material, history = conjugate_gradient!(material, ctx;
max_iter=20, tol=1e-6)
# Check convergence
print_convergence_table(history)Tutorial 4: MRI Data to Mesh
Generate a finite element mesh from MRI displacement data:
using Sentinel
# Load MRI data (Siemens DICOM format)
mre_data = read_mre_siemens("dicom_dir/", 60.0, 1.0)
# Configure mesh generation
config = HexMeshConfig(
mesh_strategy=2, # wavelength-based resolution
mu_estimate=3000.0, # estimated shear modulus [Pa]
rho_estimate=1000.0, # density [kg/m^3]
nodes_per_wavelength=8.0, # FEM nodes per shear wavelength
buffer_size=2 # boundary buffer elements
)
# Generate hex27 mesh
result = generate_hex_mesh(mre_data, config)
# Write mesh files in NLI format
write_hex_mesh_files(result, "output/brain")
# Export to VTK for visualization
export_vtk("output/brain_mesh", result)Tutorial 5: VTK Export
Export results to VTK format for visualization in ParaView:
using Sentinel
# Export mesh with displacement data
export_vtk("result", hex_mesh_result;
write_disp=true,
write_anatomical=true,
write_region=true
)
# Export convergence history to CSV
export_convergence_csv("convergence.csv", history)