Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 4 additions & 21 deletions .github/workflows/nextflow-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,19 @@ on:
branches: ["main", "dev"]
paths:
- "workflows/**"
- ".github/workflows/nextflow-ci.yml"
pull_request:
branches: ["main"]
paths:
- "workflows/**"
- ".github/workflows/nextflow-ci.yml"

jobs:
lint-and-test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4

- uses: actions/setup-java@v5.2.0
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
Expand All @@ -32,7 +30,7 @@ jobs:

- name: Install nf-test
run: |
NF_TEST_VERSION=0.9.5
NF_TEST_VERSION=$(curl -s https://api.github.com/repos/askimed/nf-test/releases/latest | jq -r .tag_name | sed 's/^v//')
wget -qO nf-test.tar.gz "https://github.com/askimed/nf-test/releases/download/v${NF_TEST_VERSION}/nf-test-${NF_TEST_VERSION}.tar.gz"
tar -xzf nf-test.tar.gz
mkdir -p "$HOME/.nf-test"
Expand All @@ -41,26 +39,11 @@ jobs:
sudo chmod +x /usr/local/bin/nf-test

- name: Lint Nextflow files
# `nextflow lint` does not load Groovy classes from `lib/`, so it
# falsely reports `Helpers` as undefined wherever the workflow calls
# `Helpers.X(...)`. We strip ANSI colour codes from the output, drop
# those known false-positives, and re-derive the exit status.
run: |
tmp=$(mktemp)
nextflow lint \
workflows/preproc/preproc_rawtiles.nf \
workflows/reconst_3d/soct_3d_reconst.nf \
workflows/reconst_2.5d/soct_2.5d_reconst.nf \
> "$tmp" 2>&1 || true
sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' "$tmp" \
| awk '/`Helpers` is not defined/ { skip = 3; next } skip > 0 { skip--; next } { print }' \
> "$tmp.filt"
cat "$tmp.filt"
if grep -qE '^Error ' "$tmp.filt"; then
echo "::error::nextflow lint reported errors (excluding Helpers false-positives)"
exit 1
fi
echo "Lint passed (Helpers false-positives ignored: lib/ classes are loaded at runtime but not by 'nextflow lint')."
workflows/reconst_2.5d/soct_2.5d_reconst.nf

- name: Validate Nextflow configs
run: |
Expand Down
9 changes: 0 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ eggs/
.eggs/
lib/
lib64/
!workflows/**/lib/
!workflows/**/lib/**
parts/
sdist/
var/
Expand Down Expand Up @@ -186,13 +184,6 @@ workflows/work/
*.nii.gz
*.sif

# Test stub-data placeholders. The `*.zarr` rule above ignores zarr directories
# wholesale; for nf-test stub runs we still need the empty directory markers
# (`.gitkeep`) tracked so the workflow's input glob finds at least one
# `mosaic_grid*.ome.zarr` directory. Re-include the directory and its keepers.
!workflows/**/tests/data/*.ome.zarr
!workflows/**/tests/data/*.ome.zarr/.gitkeep

# Config files
*.ini

Expand Down
19 changes: 11 additions & 8 deletions docs/AI_DOCUMENTATION_INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,35 @@ Complete documentation for the linumpy microscopy processing library. The librar

1. **[PIPELINE_OVERVIEW.md](PIPELINE_OVERVIEW.md)** - Complete overview of preprocessing and 3D reconstruction pipelines
2. **[NEXTFLOW_WORKFLOWS.md](NEXTFLOW_WORKFLOWS.md)** - Nextflow workflow configuration and execution guide
3. **[RECONST_2_5D_WORKFLOW.md](RECONST_2_5D_WORKFLOW.md)** - Legacy 2.5D reconstruction workflow (TIFF mosaic grids)

### Data Formats

3. **[MOSAIC_GRID_FORMAT.md](MOSAIC_GRID_FORMAT.md)** - OME-Zarr mosaic grid format specification
4. **[SHIFTS_FILE_FORMAT.md](SHIFTS_FILE_FORMAT.md)** - XY shifts CSV file format and usage
4. **[MOSAIC_GRID_FORMAT.md](MOSAIC_GRID_FORMAT.md)** - OME-Zarr mosaic grid format specification
5. **[SHIFTS_FILE_FORMAT.md](SHIFTS_FILE_FORMAT.md)** - XY shifts CSV file format and usage

---

## Feature Documentation

5. **[SLICE_CONFIG_FEATURE.md](SLICE_CONFIG_FEATURE.md)** - Slice selection and filtering system
6. **[SLICE_INTERPOLATION_FEATURE.md](SLICE_INTERPOLATION_FEATURE.md)** - Missing slice reconstruction using registration-based morphing
7. **[GPU_ACCELERATION.md](GPU_ACCELERATION.md)** - GPU acceleration using NVIDIA CUDA/CuPy
6. **[SLICE_CONFIG_FEATURE.md](SLICE_CONFIG_FEATURE.md)** - Slice selection and filtering system
7. **[SLICE_INTERPOLATION_FEATURE.md](SLICE_INTERPOLATION_FEATURE.md)** - Missing slice reconstruction using registration-based morphing
8. **[GPU_ACCELERATION.md](GPU_ACCELERATION.md)** - GPU acceleration using NVIDIA CUDA/CuPy

---

## Reference

8. **[SCRIPTS_REFERENCE.md](SCRIPTS_REFERENCE.md)** - Command-line scripts reference guide
9. **[LIBRARY_MODULES.md](LIBRARY_MODULES.md)** - Python library module documentation
9. **[SCRIPTS_REFERENCE.md](SCRIPTS_REFERENCE.md)** - Command-line scripts reference guide
10. **[LIBRARY_MODULES.md](LIBRARY_MODULES.md)** - Python library module documentation
11. **[RECONSTRUCTION_DIAGNOSTICS.md](RECONSTRUCTION_DIAGNOSTICS.md)** - Diagnostic tools for troubleshooting reconstruction artifacts
12. **[PIPELINE_PERFORMANCE_ANALYSIS.md](PIPELINE_PERFORMANCE_ANALYSIS.md)** - Pipeline performance benchmarks and optimization guide

---

## Contributing

10. **[CONTRIBUTING.md](CONTRIBUTING.md)** - Contribution guidelines
13. **[CONTRIBUTING.md](CONTRIBUTING.md)** - Contribution guidelines

---

Expand Down
14 changes: 7 additions & 7 deletions docs/GPU_ACCELERATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ linumpy supports GPU acceleration for compute-intensive operations using NVIDIA
nvidia-smi | grep "CUDA Version"

# Install linumpy with GPU support (choose your CUDA version)
pip install linumpy[gpu] # CUDA 12.x (default)
pip install linumpy[gpu-cuda11] # CUDA 11.x
pip install linumpy[gpu-cuda13] # CUDA 13.x (requires extra setup for JAX)
uv pip install 'linumpy[gpu]' # CUDA 12.x (default)
uv pip install 'linumpy[gpu-cuda11]' # CUDA 11.x
uv pip install 'linumpy[gpu-cuda13]' # CUDA 13.x (requires extra setup for JAX)

# Verify GPU
linum_gpu_info.py
Expand Down Expand Up @@ -90,18 +90,18 @@ If you prefer manual setup:

```bash
# 1. Uninstall all conflicting packages
pip uninstall -y jax jaxlib jax-cuda12-plugin nvidia-cusolver nvidia-cufft \
uv pip uninstall jax jaxlib jax-cuda12-plugin nvidia-cusolver nvidia-cufft \
nvidia-cusparse nvidia-cublas nvidia-cuda-runtime nvidia-cudnn nvidia-nvjitlink \
nvidia-cublas-cu12 nvidia-cuda-cupti-cu12 nvidia-cuda-runtime-cu12 \
nvidia-cudnn-cu12 nvidia-cufft-cu12 nvidia-cusolver-cu12 nvidia-cusparse-cu12 \
nvidia-nccl-cu12 nvidia-nvjitlink-cu12

# 2. Install JAX 0.4.23 with CUDA wheel
pip install 'jax==0.4.23' 'jaxlib==0.4.23+cuda12.cudnn89' \
uv pip install 'jax==0.4.23' 'jaxlib==0.4.23+cuda12.cudnn89' \
-f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html

# 3. Install PINNED nvidia package versions (critical - newer versions won't work!)
pip install \
uv pip install \
'nvidia-cublas-cu12==12.3.4.1' \
'nvidia-cuda-cupti-cu12==12.3.101' \
'nvidia-cuda-runtime-cu12==12.3.101' \
Expand Down Expand Up @@ -155,7 +155,7 @@ separate `_gpu.py` variant is needed.
| `linum_assess_slice_quality.py` | SSIM, morphology | 3-8x |
| `linum_aip_png.py` | Mean projection | ≤1x |
| `linum_generate_mosaic_aips.py` | Mean projection | ≤1x |
| `linum_normalize_z_intensity.py` | Scale-factor computation | varies |
| `linum_correct_bias_field.py` | N4 bias field estimation | varies |
| `linum_estimate_global_transform.py` | Phase correlation | 8-16x |

---
Expand Down
2 changes: 1 addition & 1 deletion docs/MOSAIC_GRID_FORMAT.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ slice_z00_normalize.ome.zarr
### Napari (Recommended)

```bash
pip install napari[all]
uv pip install 'napari[all]'
napari mosaic_grid_3d_z00.ome.zarr
```

Expand Down
84 changes: 29 additions & 55 deletions docs/NEXTFLOW_WORKFLOWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,21 +98,18 @@ nextflow run preproc_rawtiles.nf \
| `processes` | `1` | Parallel Python processes per task (CPU mode only) |
| `max_mosaic_forks` | `4` | Max concurrent `create_mosaic_grid` GPU jobs |
| `max_aip_forks` | `4` | Max concurrent `generate_aip` GPU jobs |
| `max_quality_forks` | `2` | Max concurrent `assess_slice_quality` GPU jobs |
| `axial_resolution` | `1.36` | Axial resolution (µm) |
| `resolution` | `-1` | Output resolution (-1 = full native resolution) |
| `sharding_factor` | `4` | Zarr sharding (NxN chunks/shard) |
| `fix_galvo_shift` | `true` | Correct galvo shifts |
| `fix_camera_shift` | `false` | Correct camera shifts |
| `preprocess` | `false` | Apply rotation/flip preprocessing (true for legacy data) |
| `galvo_confidence_threshold` | `0.6` | Minimum confidence to apply galvo fix |
| `generate_slice_config` | `true` | Generate slice_config.csv |
| `exclude_first_slices` | `1` | Number of leading slices to mark as excluded |
| `detect_galvo` | `false` | Include galvo detection results in slice_config.csv |
| `generate_previews` | `false` | Generate orthogonal view previews of mosaic grids |
| `generate_aips` | `false` | Generate AIP images from mosaic grids for QC |
| `assess_quality` | `false` | Run quality assessment and update slice_config |
| `min_quality_score` | `0.2` | Minimum quality score to include slice (0 = report only) |
| `quality_sample_depth` | `10` | Z-planes sampled per slice during quality assessment |

### Outputs

Expand Down Expand Up @@ -207,7 +204,7 @@ nextflow run soct_3d_reconst.nf \
| `fix_curvature_enabled` | `false` | Detect and compensate focal curvature artifacts |
| `fix_illum_enabled` | `true` | Fix illumination inhomogeneity (BaSiCPy algorithm) |
| `crop_interface_out_depth` | `600` | Maximum tissue depth after interface crop (µm) |
| `normalize_min_contrast` | `0.1` | Min contrast fraction to prevent over-amplification of empty slices (0–1) |


#### Tile Stitching

Expand Down Expand Up @@ -362,17 +359,6 @@ and correlation or physics-based Z-matching.
| `stack_translation_smooth_sigma` | `3.0` | Gaussian sigma (slices) for smoothing accumulated translations (0 = disabled) |
| `stack_translation_min_zcorr` | `0.2` | Min z_correlation to use a slice's translation in accumulation |

**Legacy post-hoc rehoming (for re-stacking old data):**

| Parameter | Default | Description |
|-----------|---------|-------------|
| `stitch_rehoming_enabled` | `false` | Apply one-time segment offset at re-homing event boundaries during stacking |
| `stitch_rehoming_threshold_mm` | `0.7` | Motor shift magnitude that identifies a re-homing event (mm) |
| `stitch_rehoming_use_motor` | `false` | Use motor delta instead of pairwise registration for the correction |

Modern pipelines should rely on `detect_rehoming` in common-space alignment
instead of these stacking-time corrections.

**Output pyramid:**

| Parameter | Default | Description |
Expand All @@ -390,30 +376,15 @@ The `pyramid_resolutions` parameter controls the multi-resolution pyramid in the

**Note:** Only resolutions ≥ the base `resolution` parameter will be included. For example, if `resolution = 25`, then only 25, 50, and 100 µm levels will be created.

#### Z-Intensity Normalization

Corrects slow intensity drift across serial sections after stacking. Disabled by default.

| Parameter | Default | Description |
|-----------|---------|-------------|
| `normalize_z_slices` | `false` | Enable post-stacking Z-intensity normalization |
| `znorm_mode` | `'histogram'` | Normalization mode: `histogram` (preserves contrast) or `percentile` (linear scaling) |
| `znorm_strength` | `0.5` | Correction mixing strength (0 = passthrough, 1 = full correction) |

**Histogram mode** (`znorm_mode = 'histogram'`):

| Parameter | Default | Description |
|-----------|---------|-------------|
| `znorm_tissue_threshold` | `0.02` | Minimum intensity to classify as tissue (below this left unchanged) |
#### Bias Field Correction

**Percentile mode** (`znorm_mode = 'percentile'`):
Corrects slow intensity drift and bias field across serial sections after stacking using N4 bias field correction (SimpleITK). Disabled by default.

| Parameter | Default | Description |
|-----------|---------|-------------|
| `znorm_smooth_sigma` | `10.0` | Gaussian smoothing sigma (sections); ~10 corrects ~2mm drift and preserves anatomy |
| `znorm_percentile` | `80.0` | Percentile of non-zero tissue voxels used as intensity reference |
| `znorm_max_scale` | `2.0` | Maximum correction scale factor |
| `znorm_min_scale` | `0.5` | Minimum correction scale factor |
| `correct_bias_field` | `false` | Enable post-stacking N4 bias field correction |
| `bias_mode` | `'two_pass'` | Correction mode: `per_section` (N4 per thick section), `global` (single volume pass), or `two_pass` (per-section then global) |
| `bias_strength` | `1.0` | Correction mixing strength (0 = passthrough, 1 = full correction) |

#### Atlas Registration (RAS Alignment)

Expand Down Expand Up @@ -542,7 +513,7 @@ tight image-based registration.

| Parameter | Default | Description |
|-----------|---------|-------------|
| `analyze_shifts` | `false` | Generate shifts analysis report and drift plots |
| `analyze_shifts` | `true` | Generate shifts analysis report and drift plots |
| `debug_slices` | `""` | Comma-separated slice IDs or ranges to process (e.g. `"25,26"` or `"25-29"`); leave empty to process all |

The `analyze_shifts` option runs drift analysis on the shifts file before processing, producing:
Expand All @@ -559,7 +530,6 @@ Diagnostic mode enables additional analysis processes for troubleshooting recons
| `diagnostic_mode` | `false` | Master switch: enables all diagnostic analyses |
| `analyze_rotation_drift` | `false` | Analyze cumulative rotation between slices |
| `analyze_acquisition_rotation` | `false` | Analyze acquisition-time rotation from shifts + registration |
| `analyze_tile_dilation` | `false` | Analyze tile position refinements for scale drift (works best with `max_blend_refinement_px = 0`) |
| `motor_only_stitch` | `false` | Stitch slices using motor positions only (no image registration) |
| `motor_only_stack` | `false` | Stack slices using motor positions only (no pairwise registration) |
| `compare_stitching` | `false` | Compare motor-only vs refined stitching side-by-side |
Expand Down Expand Up @@ -588,36 +558,42 @@ Diagnostic outputs are written to `{output}/diagnostics/` and include rotation p
```
output/
├── README/readme.txt
├── analyze_shifts/ # Only when analyze_shifts = true
├── resample_mosaic_grid/
├── fix_focal_curvature/
├── fix_illumination/
├── generate_aip/
├── estimate_xy_transformation/
├── stitch_3d/
├── stitch_3d_with_refinement/
├── previews/stitched_slices/ # Only when stitch_preview = true
├── beam_profile_correction/
├── crop_interface/
├── normalize/
├── detect_rehoming_events/ # Only when detect_rehoming = true
├── auto_assess_quality/ # Only when auto_assess_quality = true
├── bring_to_common_space/
├── common_space_previews/ # Only when common_space_preview = true
├── interpolate_missing_slice/ # Only when interpolate_missing_slices = true
├── finalise_interpolation/
├── register_pairwise/
├── auto_exclude_slices/ # Only when auto_exclude_enabled = true
├── stack/
│ ├── 3d_volume.ome.zarr
│ ├── 3d_volume.ome.zarr.zip
│ └── 3d_volume.png
├── normalize_z_intensity/ # Only when normalize_z_slices = true
│ └── 3d_volume_znorm.ome.zarr
│ ├── {subject}.ome.zarr
│ ├── {subject}.ome.zarr.zip
│ ├── {subject}.png
│ └── {subject}_annotated.png
├── correct_bias_field/ # Only when correct_bias_field = true
│ └── {subject}_corrected.ome.zarr
├── align_to_ras/ # Only when align_to_ras_enabled = true
│ ├── {subject}_ras.ome.zarr # RAS-aligned volume (all pyramid levels)
│ ├── {subject}_ras_transform.tfm # Registration transform (SimpleITK)
│ └── {subject}_ras_preview.png # 3-panel alignment comparison
│ ├── {subject}_ras.ome.zarr
│ ├── {subject}_ras_transform.tfm
│ └── {subject}_ras_preview.png
├── diagnostics/ # Only when diagnostic_mode = true or individual flags set
│ ├── rotation_analysis/
│ ├── acquisition_rotation/
│ ├── dilation_analysis/
│ ├── aggregated_dilation/
│ ├── motor_only_stitch/
│ ├── refined_stitch/
│ ├── motor_only_stack/
│ └── stitch_comparison/
└── {subject}_quality_report.html
└── {subject}_quality_report.html # Only when generate_report = true
```

---
Expand All @@ -632,10 +608,8 @@ Both workflows support GPU acceleration using NVIDIA CUDA via CuPy. GPU processi
|----------|---------|----------------|
| `preproc_rawtiles.nf` | `create_mosaic_grid` | Galvo detection, volume resize |
| `preproc_rawtiles.nf` | `generate_aip` | Mean projection |
| `preproc_rawtiles.nf` | `assess_slice_quality` | SSIM, edge detection (Sobel) |
| `soct_3d_reconst.nf` | `resample_mosaic_grid` | Volume resize |
| `soct_3d_reconst.nf` | `fix_illumination` | BaSiCPy background correction (JAX on GPU) |
| `soct_3d_reconst.nf` | `estimate_xy_transformation` | Phase correlation (FFT) |
| `soct_3d_reconst.nf` | `normalize` | Intensity normalization, percentile clipping |

### Usage
Expand Down Expand Up @@ -665,7 +639,7 @@ params {

For GPU support:
- NVIDIA GPU with CUDA support
- CuPy installed: `pip install cupy-cuda12x`
- CuPy installed: `uv pip install cupy-cuda12x`
- See [GPU_ACCELERATION.md](GPU_ACCELERATION.md) for detailed setup

### Expected Speedups
Expand Down
Loading