Skip to content
Merged
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
29 changes: 25 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ HASA-PAM is a Julia project for GPU-accelerated transcranial passive acoustic ma

The repository implements a reconstruction pipeline for localising acoustic sources inside the skull. The motivating application is non-invasive targeted drug delivery in the brain: if ultrasound-controllable drug carriers can be aggregated and uncaged at a chosen target, a future closed-loop system would also need feedback about whether drug-carrier or bubble clusters formed and where they are located.

This project addresses that feedback problem with transcranial PAM. Receiver recordings are time-reversed through an acoustic model, and the reconstructed intensity field is used to estimate source locations. The implementation compares a fast homogeneous angular-spectrum baseline with a skull-aware Heterogeneous Angular Spectrum Approach (HASA) reconstruction that uses a CT-derived speed-of-sound model. The current benchmark is simulation-based and uses synthetic source emissions.
This project addresses that feedback problem with transcranial PAM. While the primary focus is PAM, transcranial **focusing** (geometric and HASA delay estimation with optional k-Wave verification) is also fully implemented and accessible via CLI for both 2D and 3D domains. Receiver recordings are time-reversed through an acoustic model, and the reconstructed intensity field is used to estimate source locations. The implementation compares a fast homogeneous angular-spectrum baseline with a skull-aware Heterogeneous Angular Spectrum Approach (HASA) reconstruction that uses a CT-derived speed-of-sound model. The current benchmark is simulation-based and uses synthetic source emissions.

In the reported synthetic 3D benchmark, skull correction reduced mean localisation error from **1.77 mm** to **0.49 mm**, while the GPU implementation reduced corrected reconstruction march time from **13.28 s** to **0.23 s**.

Expand Down Expand Up @@ -213,7 +213,10 @@ For more detailed setup instructions, workflow notes, and CLI parameter referenc

### Command line entry points

The repository is meant to be used primarily from the command line. The maintained PAM entry point is `scripts/run_pam.jl`; focusing scripts are kept for the earlier transcranial focusing workflow.
The repository exposes two primary command line entry points:

- **`scripts/run_pam.jl`** — the main PAM workflow: simulate emissions, reconstruct source distributions, evaluate accuracy.
- **`scripts/run_focus.jl`** — transcranial focusing: compute geometric or HASA transmit delays, optionally verify with k-Wave, for 2D and 3D domains.

### Setup

Expand Down Expand Up @@ -256,10 +259,28 @@ julia --project=. scripts/run_pam.jl \
--recon-use-gpu=true
```

### Quick focusing example
### Quick focusing examples

2D skull-backed HASA focus:

```bash
julia --project=. scripts/run_focus.jl --estimator=hasa --medium=skull_in_water --slice-index=250
julia --project=. scripts/run_focus.jl \
--estimator=hasa \
--aberrator=skull \
--slice-index=250
```

3D HASA focus in water (no k-Wave, fast smoke test):

```bash
julia --project=. scripts/run_focus.jl \
--dimension=3 \
--estimator=hasa \
--aberrator=water \
--focus-mm=60:0:0 \
--receiver-aperture-y-mm=60 \
--receiver-aperture-z-mm=60 \
--run-kwave=false
```

### Tests
Expand Down
5 changes: 5 additions & 0 deletions docs/generate_cli_reference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ function generate_cli_reference(path=joinpath(@__DIR__, "src", "cli", "parameter
println(io)
_write_option_table(io, category_options)
println(io)
if category == "Medium"
println(io, "!!! warning \"Scan-specific defaults\"")
println(io, " The defaults for `--slice-index`, `--skull-transducer-distance-mm`, and `--hu-bone-thr` are calibrated to the specific CT scan used during development. Using a different scan without adjusting these values will likely produce an incorrect skull medium.")
println(io)
end
end
end

Expand Down
4 changes: 2 additions & 2 deletions docs/src/cli/overview.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# CLI Overview

The maintained entry point, and the main objective of this repository, is PAM:
The primary entry point for passive acoustic mapping:

```bash
julia --project=. scripts/run_pam.jl --option=value
```

The focusing scripts are also available for reference to the earlier focusing workflow:
Transcranial focusing (geometric and HASA delay estimation, 2D and 3D):

```bash
julia --project=. scripts/run_focus.jl --option=value
Expand Down
4 changes: 4 additions & 0 deletions docs/src/cli/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ For practical guidance, start with [Running PAM](@ref) before tuning individual
| `--skull-transducer-distance-mm` | `30` | mm | skull | | Distance from the receiver/transducer plane to the outer skull surface. |
| `--hu-bone-thr` | `200` | HU | skull | | Hounsfield-unit threshold used to identify bone in CT data. |

!!! warning "Scan-specific defaults"
The defaults for `--slice-index`, `--skull-transducer-distance-mm`, and `--hu-bone-thr` are calibrated to the specific CT scan used during development. Using a different scan without adjusting these values will likely produce an incorrect skull medium.

## Simulation

| Option | Default | Value | Applies to | Choices | Description |
Expand All @@ -156,3 +159,4 @@ For practical guidance, start with [Running PAM](@ref) before tuning individual
| `--recon-min-window-energy-ratio` | `0.001` | ratio | windowed | | Skips windows whose energy is below this fraction of the maximum window energy. |
| `--recon-progress` | `false` | bool | PAM | | Prints reconstruction progress updates. |
| `--window-batch` | `1` | integer | windowed GPU | | Number of reconstruction windows batched together on the GPU. |

66 changes: 53 additions & 13 deletions docs/src/cli/run-focus.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Running Focus

The focusing scripts are retained only as reference material from the earlier transcranial focusing workflow. The main objective of this repository is PAM; these scripts are useful for comparing geometric and HASA focusing corrections through water or a CT-backed skull medium.
`scripts/run_focus.jl` computes transcranial transmit delays (geometric or HASA) for 2D and 3D domains, optionally verifying focus quality with k-Wave. It supports both water and CT-backed skull media. `scripts/compare_focus_estimators.jl` runs both estimators side-by-side and writes a comparison figure.

## Single Focusing Case

Expand All @@ -9,31 +9,61 @@ Default skull-backed HASA case:
```bash
julia --project=. scripts/run_focus.jl \
--estimator=hasa \
--medium=skull_in_water \
--aberrator=skull \
--slice-index=250
```

Centered target at 60 mm below the transducer:

```bash
julia --project=. scripts/run_focus.jl \
--dimension=2 \
--estimator=hasa \
--medium=skull_in_water \
--aberrator=skull \
--placement=fixed_transducer \
--slice-index=250 \
--lateral-cm=0.0 \
--focal-cm=6.0
--focus-mm=60:0
```

3D water-backed HASA setup dry enough for checking the focusing delays without k-Wave:

```bash
julia --project=. scripts/run_focus.jl \
--dimension=3 \
--estimator=hasa \
--aberrator=water \
--focus-mm=60:0:0 \
--receiver-aperture-y-mm=60 \
--receiver-aperture-z-mm=60 \
--run-kwave=false
```

3D skull-backed k-Wave outward propagation without inward verification:

```bash
julia --project=. scripts/run_focus.jl \
--dimension=3 \
--estimator=hasa \
--aberrator=skull \
--outward-propagation=kwave \
--verify-inward-kwave=false \
--focus-mm=30:0:0 \
--slice-index=250 \
--skull-transducer-distance-mm=5 \
--receiver-aperture-y-mm=20 \
--receiver-aperture-z-mm=20
```

Target 30 mm below the inner skull:

```bash
julia --project=. scripts/run_focus.jl \
--dimension=2 \
--estimator=hasa \
--medium=skull_in_water \
--aberrator=skull \
--placement=fixed_focus_depth \
--slice-index=250 \
--focal-cm=6.0 \
--focus-mm=60:0 \
--focus-depth-from-inner-skull-mm=30
```

Expand All @@ -50,13 +80,23 @@ julia --project=. scripts/compare_focus_estimators.jl \
- `--ct-path`: DICOM folder for CT-backed skull runs.
- `--slice-index`: CT slice used for the 2D focusing medium.
- `--frequency-mhz`: transmit frequency.
- `--focal-cm`: transducer-to-focus distance for fixed-transducer placement, or transducer distance to the resolved target for fixed-depth placement.
- `--lateral-cm`: lateral target offset.
- `--aperture-cm`: transducer aperture width.
- `--dimension`: `2` or `3`.
- `--focus-mm`: target coordinates. Use `depth:lateral` in 2D and `depth:y:z` in 3D.
- `--receiver-aperture-mm`: transducer aperture width. In 3D, `--receiver-aperture-y-mm` and `--receiver-aperture-z-mm` override each axis independently.
- `--estimator`: `geometric` or `hasa`.
- `--medium`: `water` or `skull_in_water`.
- `--placement`: `auto`, `fixed_transducer`, or `fixed_focus_depth`.
- `--focus-depth-from-inner-skull-mm`: target depth below the inner skull for fixed-depth placement.
- `--aberrator`: `none`, `water`, or `skull`.
- `--placement`: `auto`, `fixed_transducer`, or `fixed_focus_depth` (2D only).
- `--focus-depth-from-inner-skull-mm`: target depth below the inner skull for fixed-depth placement (2D only).
- `--skull-transducer-distance-mm`: gap between the outer skull surface and the transducer plane.
- `--outward-propagation`: `angular_spectrum` or `kwave`.
- `--verify-inward-kwave`: set `false` to skip the return pressure simulation after computing transmit delays.
- `--run-kwave`: legacy shorthand; setting it to `false` also skips inward verification.
- `--kwave-use-gpu`: set `true` to run k-Wave on GPU.
- `--transverse-mm`: transverse grid extent (mm). In 3D, `--transverse-y-mm` and `--transverse-z-mm` override each axis independently.
- `--dx-mm`, `--dz-mm`: lateral and axial grid spacing. `--dy-mm` overrides lateral spacing for the y axis in 3D.
- `--axial-mm`: axial domain extent; defaults to `auto` (derived from focus depth and padding).
- `--axial-padding`: multiplicative padding applied to the focus depth when computing the axial domain size (default `1.5`).
- `--out-dir`: override the automatically generated output directory.

`scripts/run_focus.jl` writes `summary.json`, `result.jld2`, and `pressure.png`. `scripts/compare_focus_estimators.jl` writes `summary.json` and `comparison.png`.
Focus runs also write `sensor_timings.png`, which visualizes the computed transmit delay and normalized amplitude at the active sensor/aperture elements.
3 changes: 3 additions & 0 deletions docs/src/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ The private CT data used during development is not distributed with this reposit

Override this with `--ct-path=/path/to/dicom-folder` for skull-backed runs. Homogeneous runs with `--aberrator=none` do not need CT data.

!!! warning "Scan-specific defaults"
Parameters such as `--slice-index`, `--skull-transducer-distance-mm`, and `--hu-bone-thr` are set to values that work with the specific CT scan used during development of this project. They will likely need to be adjusted for a different scan to ensure the skull medium is constructed correctly.

## First PAM Run

A small homogeneous point-source run is the fastest way to confirm the CLI works:
Expand Down
4 changes: 2 additions & 2 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# TranscranialFUS Documentation

`TranscranialFUS` is a Julia project whose main objective is passive acoustic mapping (PAM) for transcranial ultrasound. The maintained workflow is `scripts/run_pam.jl`; the older focusing scripts are documented only as reference material.
`TranscranialFUS` is a Julia project whose primary objective is passive acoustic mapping (PAM) for transcranial ultrasound. The main workflow is `scripts/run_pam.jl`. Transcranial **focusing** (geometric and HASA delay estimation, with optional k-Wave verification) is also fully implemented and available via `scripts/run_focus.jl` for both 2D and 3D domains.

Start with [Getting Started](@ref), then use [Running PAM](@ref) for examples and [PAM CLI Parameters](@ref) for the generated option reference. Supporting pages cover CLI conventions, workflow, outputs, benchmark, troubleshooting, and focusing scripts kept from the earlier workflow.
Start with [Getting Started](@ref), then use [Running PAM](@ref) for examples and [PAM CLI Parameters](@ref) for the generated option reference. See [Running Focus](@ref) for the focusing CLI. Supporting pages cover CLI conventions, workflow, outputs, benchmark, and troubleshooting.

The code is research-oriented and assumes access to local CT data for skull-backed examples. Homogeneous water examples do not require CT data.
119 changes: 119 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Script Examples

## 3D Focusing

Fast delay/HASA smoke test without running k-Wave:

```bash
julia --project=. scripts/run_focus.jl \
--dimension=3 \
--aberrator=water \
--estimator=hasa \
--focus-mm=12:0:0 \
--dx-mm=1 \
--dy-mm=1 \
--dz-mm=1 \
--transverse-mm=21 \
--receiver-aperture-mm=11 \
--run-kwave=false \
--out-dir=/private/tmp/focus3d_smoke
```

Use k-Wave for the outward focus-to-aperture propagation, then skip the inward
verification simulation:

```bash
julia --project=. scripts/run_focus.jl \
--dimension=3 \
--aberrator=skull \
--estimator=hasa \
--outward-propagation=kwave \
--verify-inward-kwave=false \
--focus-mm=30:0:0 \
--slice-index=250 \
--skull-transducer-distance-mm=5 \
--receiver-aperture-y-mm=20 \
--receiver-aperture-z-mm=20
```

3D water focusing with k-Wave enabled:

```bash
julia --project=. scripts/run_focus.jl \
--dimension=3 \
--aberrator=water \
--estimator=geometric \
--focus-mm=60:0:0 \
--transverse-y-mm=80 \
--transverse-z-mm=80 \
--receiver-aperture-y-mm=60 \
--receiver-aperture-z-mm=60
```

Kwave outward, no verification with mac skull path
```bash
julia --project=. scripts/run_focus.jl \
--ct-path="$HOME/INI_code/Ultrasound/DIRU_20240404_human_skull_phase_correction_1_2_(skull_Normal)/DICOM/PAT_0000/STD_0000/SER_0002/OBJ_0001" \
--dimension=3 \
--aberrator=skull \
--focus-mm=30:0:0 \
--outward-propagation=kwave \
--verify-inward-kwave=false \
--slice-index=250 \
--skull-transducer-distance-mm=5 \
--receiver-aperture-y-mm=20 \
--receiver-aperture-z-mm=20 \
--transverse-y-mm=30 \
--transverse-z-mm=30 \
--axial-padding=1.2
```

3D CT-backed skull focusing:

```bash
julia --project=. scripts/run_focus.jl \
--ct-path="$HOME/INI_code/Ultrasound/DIRU_20240404_human_skull_phase_correction_1_2_(skull_Normal)/DICOM/PAT_0000/STD_0000/SER_0002/OBJ_0001" \
--dimension=3 \
--aberrator=skull \
--estimator=hasa \
--focus-mm=30:0:0 \
--slice-index=250 \
--skull-transducer-distance-mm=5 \
--receiver-aperture-y-mm=20 \
--receiver-aperture-z-mm=20
```

## 2D Focusing

Fast 2D smoke test without running k-Wave:

```bash
julia --project=. scripts/run_focus.jl \
--dimension=2 \
--aberrator=water \
--estimator=hasa \
--focus-mm=12:0 \
--dx-mm=1 \
--dz-mm=1 \
--transverse-mm=21 \
--receiver-aperture-mm=11 \
--run-kwave=false \
--out-dir=/private/tmp/focus2d_smoke
```

2D CT-backed skull focusing at fixed depth below the inner skull:

```bash
julia --project=. scripts/run_focus.jl \
--dimension=2 \
--aberrator=skull \
--estimator=hasa \
--placement=fixed_focus_depth \
--focus-mm=60:0 \
--focus-depth-from-inner-skull-mm=30 \
--slice-index=250
```

`--focus-mm` is `depth:lateral` in 2D and `depth:y:z` in 3D. Outputs are written under `outputs/` unless `--out-dir` is provided.
`--outward-propagation=kwave` estimates transmit delays by simulating from the focus to the aperture; the default `angular_spectrum` uses the geometric/HASA path. `--verify-inward-kwave=false` skips the return pressure-field verification step.
Every focus run writes `sensor_timings.png`, showing the per-element transmit delay and normalized amplitude at the active sensor/aperture.
Loading
Loading