Skip to content

Troubleshooting

This page documents common failure modes encountered in AortaCFD simulations, their root causes, and recommended solutions.


Mesh Generation Failures

"No cells in mesh"

Cause: The scale_factor in config.json does not match the STL file units. The geometry is either too large (extends beyond the background mesh domain) or too small (collapsed to a point).

Solution: Verify the STL units and set the correct scale factor:

STL Units scale_factor
Millimetres 0.001
Centimetres 0.01
Metres 1.0
# Check STL bounding box (in original units)
surfaceCheck constant/triSurface/wall_aorta.stl

"locationInMesh outside domain"

Cause: The automatically computed interior point lies outside the geometry, typically because the STL surface is not watertight (gaps between patches).

Solution:

  1. Verify that all patches form a closed surface: surfaceCheck constant/triSurface/wall_aorta.stl
  2. Check for gaps between inlet/outlet patches and the wall patch in ParaView
  3. AortaCFD auto-computes the interior point via ray-casting; a non-watertight geometry causes this to fail

"Boundary layer failure" or low layer coverage

Cause: Prismatic layers cannot fit on small patches (especially outlet patches) or in regions of high surface curvature.

Solution:

"boundary_layers": {
    "num_layers": 3,
    "min_thickness": 0.2,
    "expansion_ratio": 1.15
}

Reducing num_layers from 5 to 3 and increasing min_thickness from 0.1 to 0.2 often resolves layer generation failures. AortaCFD automatically retries with relaxed settings if the initial attempt fails.

checkMesh reports high non-orthogonality or skewness

Cause: Complex geometry (tight curvatures, small branches) or misaligned geometry with the coordinate system.

Solution:

  1. AortaCFD aligns geometry via PCA automatically; verify alignment is correct
  2. Increase cells_per_diameter (finer mesh often improves quality metrics)
  3. Use the regenerate-numerics step to adapt numerical schemes to the mesh quality:
    python run_patient.py <case> --update <run_path> --steps regenerate-numerics
    
  4. If quality is very poor, switch to the robust profile

Solver Failures

"PIMPLE: Not converged" every timestep

Cause: The residual target is below the convergence floor created by explicit pressure relaxation. The solver burns all outer iterations without reaching the target.

Solution:

  1. Use the robust profile (relaxed residual targets that sit above the floor):
    python run_patient.py <case> --profile robust
    
  2. Or increase the residual tolerance in the configuration

deltaT collapses to very small values (1e-100)

Cause: The PIMPLE outer loop diverges, typically during diastolic backflow. Adaptive time-stepping reduces deltaT to maintain stability, eventually collapsing.

Solution:

  1. Enable backflow stabilisation (should be on by default):
    "windkessel_settings": { "enable_stabilization": true, "betaT": 0.3 }
    
  2. Use the robust profile
  3. Check mesh quality -- high skewness near outlets exacerbates backflow instability

"Floating point exception" (NaN)

Cause: The solution contains NaN values, typically from division by zero in the pressure equation or unphysical velocity magnitudes.

Solution:

  1. Check mesh quality: cat logs/log.checkMesh
  2. Verify inlet data: ensure the CSV waveform has no negative flow rates at the start
  3. Try a different cells_per_diameter (both too coarse and too fine can cause issues)
  4. Ensure scale_factor is correct (wrong scaling produces extreme velocities)

"FOAM FATAL ERROR: cannot find file"

Cause: A required OpenFOAM dictionary or field file is missing, typically because the case step was not run or was run with a different configuration.

Solution:

python run_patient.py <case> --update <run_path> --steps case

This regenerates all OpenFOAM dictionaries without affecting the mesh.


Boundary Condition Issues

Unphysical pressure values (> 200 mmHg or < 40 mmHg)

Cause: Incorrect Windkessel parameters, typically from wrong blood pressure values or extreme outlet geometries.

Solution:

  1. Verify systolic_pressure and diastolic_pressure in config (should be in mmHg)
  2. Check the reports/inlet_audit.json for the computed mean flow rate -- is it physiologically reasonable?
  3. Check each outlet's R, C, Z values in 0/p -- very large R produces high pressure

No flow at outlets

Cause: The outlet patches may not be correctly identified in the geometry configuration.

Solution:

  1. Verify that outlet_keywords_ordered in config matches the STL filenames
  2. Open the mesh in ParaView and confirm that outlet patches exist and are correctly positioned

Post-Processing Issues

TAWSS/OSI not computed (zero values)

Cause: Runtime field averaging was not enabled, or the simulation did not run long enough to accumulate averaging data.

Solution:

  1. Ensure hemodynamics runtime functions are enabled:
    "hemodynamics": {
        "runtime_functions": { "wallShearStress": true, "fieldAverage": true }
    }
    
  2. Minimum simulation duration: (skip_cycles + 1) * cardiac_cycle_period
  3. Re-run post-processing: python run_patient.py --postprocess <run_path>

Maximum WSS is unrealistically high (> 100 Pa)

Cause: Mesh artifacts at refinement boundaries or sharp geometric features produce single-cell WSS spikes. This is expected.

Solution: Use percentile-based metrics (P95, P99) instead of maximum values. AortaCFD reports these automatically. The maximum is included for reference but should not be used for clinical interpretation.


Restarting a Crashed Simulation

# Check available time directories
ls output/<case>/run_xxx/openfoam/ | grep "^0\." | sort -g | tail -5

# Re-run solver (automatically restarts from latest saved time)
python run_patient.py <case> --update output/<case>/run_xxx --steps solver

If the crash occurs at a specific simulation time repeatedly, consider:

  1. Switching to the robust profile for the remainder of the simulation
  2. Reducing maxCo in the configuration
  3. Enabling or increasing backflow stabilisation (betaT: 0.3 to 0.5)

Diagnostic Commands

# Check mesh quality
cat output/<case>/run_xxx/openfoam/logs/log.checkMesh

# Check solver convergence
tail -50 output/<case>/run_xxx/openfoam/logs/log.solver

# Count PIMPLE iterations per timestep
grep "PIMPLE: Converged in" logs/log.solver | awk '{print $NF}' | sort | uniq -c

# Check inlet audit
cat output/<case>/run_xxx/reports/inlet_audit.json

# View full resolved configuration
cat output/<case>/run_xxx/reports/merged_config.json

Found an issue or have a suggestion for this page?

Open a GitHub issue