aind-ibl-ephys-alignment-preprocessing 0.5.2__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aind_ibl_ephys_alignment_preprocessing-0.7.0/AGENTS.md +7 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/CHANGELOG.md +28 -0
- aind_ibl_ephys_alignment_preprocessing-0.7.0/CLAUDE.md +3 -0
- aind_ibl_ephys_alignment_preprocessing-0.5.2/CLAUDE.md → aind_ibl_ephys_alignment_preprocessing-0.7.0/CONTRIBUTING.md +10 -3
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/PKG-INFO +192 -32
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/README.md +190 -31
- aind_ibl_ephys_alignment_preprocessing-0.7.0/docs/external_asset_references.md +201 -0
- aind_ibl_ephys_alignment_preprocessing-0.7.0/docs/source/data_contracts.md +10 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/docs/source/index.md +1 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/pyproject.toml +6 -1
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/_async/histology.py +3 -2
- aind_ibl_ephys_alignment_preprocessing-0.7.0/src/aind_ibl_ephys_alignment_preprocessing/_constants.py +34 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/datapackage.py +40 -11
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/discovery.py +83 -8
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/histology.py +3 -2
- aind_ibl_ephys_alignment_preprocessing-0.7.0/src/aind_ibl_ephys_alignment_preprocessing/manifest_builder.py +298 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/registration_frame.py +113 -5
- aind_ibl_ephys_alignment_preprocessing-0.7.0/src/aind_ibl_ephys_alignment_preprocessing/scripts/build_manifest.py +42 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/stages.py +13 -2
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/types.py +81 -12
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/validation.py +38 -0
- aind_ibl_ephys_alignment_preprocessing-0.7.0/tests/sidecar_fixtures.py +43 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_datapackage.py +2 -1
- aind_ibl_ephys_alignment_preprocessing-0.7.0/tests/test_manifest_builder.py +160 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_registration_override.py +12 -21
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_stages.py +23 -0
- aind_ibl_ephys_alignment_preprocessing-0.7.0/tests/test_template_to_ccf_override.py +254 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/uv.lock +4 -2
- aind_ibl_ephys_alignment_preprocessing-0.5.2/docs/external_asset_references.md +0 -417
- aind_ibl_ephys_alignment_preprocessing-0.5.2/src/aind_ibl_ephys_alignment_preprocessing/_constants.py +0 -18
- aind_ibl_ephys_alignment_preprocessing-0.5.2/src/aind_ibl_ephys_alignment_preprocessing/co_asset_resolver.py +0 -596
- aind_ibl_ephys_alignment_preprocessing-0.5.2/tests/test_co_asset_resolver.py +0 -454
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/.copier-answers.yml +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/.github/ISSUE_TEMPLATE/user-story.md +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/.github/dependabot.yml +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/.github/workflows/bump-call.yml +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/.github/workflows/ci-call.yml +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/.github/workflows/docs-ci.yml +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/.github/workflows/publish-call.yml +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/.gitignore +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/.python-version +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/.readthedocs.yaml +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/LICENSE +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/docs/source/_static/dark-logo.svg +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/docs/source/_static/favicon.ico +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/docs/source/_static/light-logo.svg +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/docs/source/api.rst +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/docs/source/conf.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/scripts/run_linters_and_checks.sh +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/__init__.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/_async/__init__.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/_async/concurrency.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/_async/ephys.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/_async/pipeline.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/_async/probes.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/_timing.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/coverage.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/datapackage_schema.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/ephys.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/pipeline.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/probes.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/py.typed +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/schemas/aind-ibl-ephys-alignment-datapackage/3.1.0/datapackage.schema.json +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/schemas/aind-ibl-ephys-alignment-datapackage/3.2.0/datapackage.schema.json +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/schemas/aind-ibl-ephys-alignment-datapackage/4.0.0/datapackage.schema.json +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/schemas/aind-ibl-ephys-alignment-datapackage/4.1.0/datapackage.schema.json +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/scripts/__init__.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/scripts/export_datapackage_schema.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/src/aind_ibl_ephys_alignment_preprocessing/scripts/run.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/__init__.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_ants_domain.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_coverage.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_datapackage_schema.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_example.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_geometry_sidecar.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_registration_frame.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_resample.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_sorting_detection.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_sync_async_parity.py +0 -0
- {aind_ibl_ephys_alignment_preprocessing-0.5.2 → aind_ibl_ephys_alignment_preprocessing-0.7.0}/tests/test_timing.py +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Agent Instructions
|
|
2
|
+
|
|
3
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md) before making changes. It is the
|
|
4
|
+
shared guide for development commands, architecture, and validation.
|
|
5
|
+
|
|
6
|
+
Keep shared development guidance in CONTRIBUTING.md and agent-specific
|
|
7
|
+
instructions here. Keep CLAUDE.md as a pointer to this file.
|
|
@@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## v0.7.0 (2026-10-23)
|
|
9
|
+
|
|
10
|
+
### BREAKING CHANGE
|
|
11
|
+
|
|
12
|
+
- registration_asset directories must carry
|
|
13
|
+
ls_to_template_transform_information.json or transform_information.json, and
|
|
14
|
+
template_to_ccf_asset requires a registration_asset.
|
|
15
|
+
|
|
16
|
+
### Feat
|
|
17
|
+
|
|
18
|
+
- write template_to_ccf_asset from the manifest mapping
|
|
19
|
+
|
|
20
|
+
### Fix
|
|
21
|
+
|
|
22
|
+
- refuse override transforms whose frame or template is unverified
|
|
23
|
+
- keep per-brain override columns on the rows discover keeps
|
|
24
|
+
|
|
25
|
+
## v0.6.0 (2026-10-22)
|
|
26
|
+
|
|
27
|
+
### Feat
|
|
28
|
+
|
|
29
|
+
- add per-brain template_to_ccf_asset manifest column
|
|
30
|
+
- add manifest builder
|
|
31
|
+
|
|
32
|
+
### Fix
|
|
33
|
+
|
|
34
|
+
- match override transforms through the S3 cache prefix
|
|
35
|
+
|
|
8
36
|
## v0.5.2 (2026-09-30)
|
|
9
37
|
|
|
10
38
|
### Fix
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Contributing
|
|
2
2
|
|
|
3
|
-
This
|
|
3
|
+
This is the main development guide for human contributors and coding agents.
|
|
4
|
+
Agent-specific instructions are in [AGENTS.md](AGENTS.md).
|
|
4
5
|
|
|
5
6
|
## Commands
|
|
6
7
|
|
|
@@ -42,6 +43,12 @@ Always use `uv run` to execute commands, `uv add` to add dependencies, and `uv s
|
|
|
42
43
|
|
|
43
44
|
## Architecture
|
|
44
45
|
|
|
46
|
+
Before changing datapackage fields, asset references, output layout, or
|
|
47
|
+
channel/shank joins, read
|
|
48
|
+
[the datapackage and external asset contract](docs/external_asset_references.md).
|
|
49
|
+
Keep machine-specific locations in resolver configuration and preserve the
|
|
50
|
+
convention-loaded ephys collection contents as well as explicit references.
|
|
51
|
+
|
|
45
52
|
This is a Python package using a `src/` layout. Source code lives in `src/aind_ibl_ephys_alignment_preprocessing/`, tests in `tests/`.
|
|
46
53
|
|
|
47
54
|
- Build system: hatchling
|
|
@@ -72,7 +79,7 @@ src/aind_ibl_ephys_alignment_preprocessing/
|
|
|
72
79
|
probes.py # Per-probe annotation loading and coordinate conversion
|
|
73
80
|
ephys.py # Sync ephys extraction wrapper (delegates to aind-ephys-ibl-gui-conversion)
|
|
74
81
|
pipeline.py # Sync orchestrator: run_pipeline()
|
|
75
|
-
|
|
82
|
+
datapackage.py # Output datapackage.json generation, asset references, schema 4.1.0
|
|
76
83
|
scripts/run.py # CLI entry point: aind-ibl-preprocess
|
|
77
84
|
_async/
|
|
78
85
|
concurrency.py # IO lane throttling (per-path semaphores), EphysCoordinator, thread helpers
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: aind-ibl-ephys-alignment-preprocessing
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Library to prepare histology and ephys for the IBL ephys alignment GUI
|
|
5
5
|
Project-URL: Repository, https://github.com/AllenNeuralDynamics/aind-ibl-ephys-alignment-preprocessing/
|
|
6
6
|
Project-URL: Issues, https://github.com/AllenNeuralDynamics/aind-ibl-ephys-alignment-preprocessing/issues
|
|
@@ -19,6 +19,7 @@ Requires-Dist: aind-registration-utils>=0.4
|
|
|
19
19
|
Requires-Dist: aind-s3-cache>=0.1
|
|
20
20
|
Requires-Dist: aind-zarr-utils>=0.11.2
|
|
21
21
|
Requires-Dist: antspyx>=0.3.0
|
|
22
|
+
Requires-Dist: boto3
|
|
22
23
|
Requires-Dist: filelock
|
|
23
24
|
Requires-Dist: iblatlas>=0.4.0
|
|
24
25
|
Requires-Dist: numpy>=1.21.0
|
|
@@ -256,7 +257,8 @@ before a column existed stays valid.
|
|
|
256
257
|
| `probe_name` | *legacy* | Alias for `ephys_collection`. |
|
|
257
258
|
| `probe_shank` | *legacy* | Alias for both `histology_shank` and `ephys_shank`. |
|
|
258
259
|
| `surface_finding` | *null* | Path (relative to `data_root`) to a surface-finding file. |
|
|
259
|
-
| `registration_asset` | *null* | Path
|
|
260
|
+
| `registration_asset` | *null* | Path relative to `data_root` to a replacement registration directory, e.g. `SmartSPIM_750108_reg/ccf_Ex_639_Em_667`. One value per brain; all nonblank rows must agree. See [Separate registration asset](#separate-registration-asset) for its contents and coordinate requirements. |
|
|
261
|
+
| `template_to_ccf_asset` | *null* | Path relative to `data_root` to the template-to-CCF registration of the template `registration_asset` was registered to, when that is not the SmartSPIM LCA template. One value per brain, like `registration_asset`. See [Separate template-to-CCF registration](#separate-template-to-ccf-registration). |
|
|
260
262
|
|
|
261
263
|
**Constraints:**
|
|
262
264
|
- All rows must have the same `mouseid`.
|
|
@@ -281,6 +283,52 @@ mouse001,2024-06-01_rec_sorted,track_annotations_probeB_shank1,B0001,probeB,Prob
|
|
|
281
283
|
mouse001,2024-06-01_rec_sorted,track_annotations_quad_shank3,Q0001,quad0,ProbeD,3,0
|
|
282
284
|
```
|
|
283
285
|
|
|
286
|
+
#### Building a manifest from a mapping
|
|
287
|
+
|
|
288
|
+
Most of a manifest repeats or follows from two choices: which sorted recording each session uses,
|
|
289
|
+
and which stream each annotated track was recorded on. `aind-ibl-build-manifest` takes only those,
|
|
290
|
+
in a TOML file, and derives the rest. Track names are never parsed, because annotators follow no
|
|
291
|
+
naming convention.
|
|
292
|
+
|
|
293
|
+
```toml
|
|
294
|
+
mouseid = "837772"
|
|
295
|
+
annotation = "837772-probe-annotations-CK-2026-09-29.json" # relative to this file
|
|
296
|
+
# registration_asset = "..." # optional, per brain
|
|
297
|
+
# template_to_ccf_asset = "..." # optional, per brain
|
|
298
|
+
|
|
299
|
+
[[session]]
|
|
300
|
+
sorted_recording = "ecephys_837772_2026-06-27_14-08-21_sorted_2026-08-27_18-59-49"
|
|
301
|
+
# surface_finding = "..." # optional
|
|
302
|
+
|
|
303
|
+
[session.tracks]
|
|
304
|
+
"732_MD_1" = "46101-1" # one shank of a split quad-base probe
|
|
305
|
+
"733_BLA" = "46810" # a single-stream probe
|
|
306
|
+
"740_PL" = { stream = "45883", shank = 1 } # one shank of a single-stream multi-shank probe; the first shank is 1
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
aind-ibl-build-manifest 837772.toml -o manifest_837772.csv [--data-root /data]
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
A stream is the collection parsed from the sort's `postprocessed/` analyzer names. They are listed
|
|
314
|
+
from a copy mounted under `--data-root`, or else unsigned from that sort's prefix in
|
|
315
|
+
`aind-open-data`. How the columns are derived:
|
|
316
|
+
|
|
317
|
+
- `probe_file` is the annotation file's name without its extension.
|
|
318
|
+
- **Split quad-base probe:** a stream `<probe>-<N>`, when the sort also holds another
|
|
319
|
+
`<probe>-<M>`, gets `logical_probe = <probe>`, `histology_shank = N - 1` and `ephys_shank = 0`.
|
|
320
|
+
- **Any other stream** is its own `logical_probe`. Its shanks stay blank, or both take the given
|
|
321
|
+
shank's index.
|
|
322
|
+
|
|
323
|
+
The build writes nothing if any of these fail, and it reports every failure:
|
|
324
|
+
- every stream in each sort has a track, and every assigned stream is in its sort;
|
|
325
|
+
- every track is a layer of the annotation file with at least two points;
|
|
326
|
+
- no track is assigned twice;
|
|
327
|
+
- a split stream has exactly one track, and the tracks sharing any other stream have distinct
|
|
328
|
+
shanks.
|
|
329
|
+
|
|
330
|
+
Annotated layers left out of the mapping are printed as notes, so a missed track gets noticed.
|
|
331
|
+
|
|
284
332
|
### Neuroglancer JSON
|
|
285
333
|
|
|
286
334
|
A Neuroglancer state JSON file that contains image source URIs pointing to the
|
|
@@ -291,7 +339,136 @@ and any additional channels.
|
|
|
291
339
|
The asset directory must contain:
|
|
292
340
|
- `image_tile_fusing/OMEZarr/<channel>.zarr/` -- fused OME-Zarr volumes
|
|
293
341
|
- `image_atlas_alignment/<registration_channel_stem>/` -- ANTs registration
|
|
294
|
-
outputs: the light-sheet to template affine and inverse warp
|
|
342
|
+
outputs: the light-sheet to template affine and inverse warp (or supply a
|
|
343
|
+
separate registration asset as described below)
|
|
344
|
+
|
|
345
|
+
### Separate registration asset
|
|
346
|
+
|
|
347
|
+
Set the manifest's optional `registration_asset` column to the transform
|
|
348
|
+
directory relative to `data_root`:
|
|
349
|
+
|
|
350
|
+
```csv
|
|
351
|
+
mouseid,sorted_recording,probe_file,histology_track_id,ephys_collection,registration_asset
|
|
352
|
+
750108,recording_sorted,probeA,A0001,ProbeA,SmartSPIM_750108_reg/ccf_Ex_639_Em_667
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Use one path per brain; conflicting nonblank values fail. An absent or blank
|
|
356
|
+
column uses the stitched asset's registration.
|
|
357
|
+
|
|
358
|
+
The directory must contain `ls_to_template_SyN_0GenericAffine.mat`,
|
|
359
|
+
`ls_to_template_SyN_1InverseWarp.nii.gz` and a geometry sidecar (below): ANTs
|
|
360
|
+
SyN outputs registering this brain's selected channel to the SmartSPIM LCA
|
|
361
|
+
template, or to another template whose CCF registration
|
|
362
|
+
`template_to_ccf_asset` (below) supplies.
|
|
363
|
+
|
|
364
|
+
The final directory name selects the channel after stripping a leading
|
|
365
|
+
`ccf_`. For this example, the stitched asset must contain
|
|
366
|
+
`image_tile_fusing/OMEZarr/Ex_639_Em_667.zarr/`. Images and metadata come
|
|
367
|
+
from the stitched asset; the override needs only transforms and their sidecar.
|
|
368
|
+
|
|
369
|
+
Every separate registration needs a geometry sidecar beside the transforms;
|
|
370
|
+
a directory without one fails. Preprocessing checks
|
|
371
|
+
`ls_to_template_transform_information.json`, then `transform_information.json`.
|
|
372
|
+
Its `moving_domain` must describe the actual registration input in LPS
|
|
373
|
+
millimeters and match the selected volume's native or pipeline-anchored frame.
|
|
374
|
+
Its `fixed_domain` must match the template the template-to-CCF chain starts
|
|
375
|
+
from: the SmartSPIM LCA template unless `template_to_ccf_asset` is set. Missing
|
|
376
|
+
or incompatible domains fail, since a wrong frame or template still puts the
|
|
377
|
+
probes somewhere plausible.
|
|
378
|
+
|
|
379
|
+
**QC:** Additional-channel CCF volumes (`emit_qc=True`) also need
|
|
380
|
+
`ls_to_template_SyN_1Warp.nii.gz` in the override directory; without it the
|
|
381
|
+
QC warp fails rather than falling back to the stitched asset's registration.
|
|
382
|
+
|
|
383
|
+
#### Generate the sidecar from ANTs outputs
|
|
384
|
+
|
|
385
|
+
Use the actual fixed template and moving histology images passed to ANTs,
|
|
386
|
+
including any preprocessing of their geometry. Transform files alone cannot
|
|
387
|
+
recover these domains. Headers must be 3D, axis-aligned, and in millimeters.
|
|
388
|
+
|
|
389
|
+
Run `uv sync` in the preprocessing library checkout, then save this as
|
|
390
|
+
`generate_registration_sidecar.py`:
|
|
391
|
+
|
|
392
|
+
```python
|
|
393
|
+
import sys
|
|
394
|
+
from pathlib import Path
|
|
395
|
+
|
|
396
|
+
import SimpleITK as sitk
|
|
397
|
+
from aind_ants_transform_sidecar import dump_package, load_package
|
|
398
|
+
from aind_registration_utils.domains import ImageHeader, make_syn_sidecar
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def read_header(path):
|
|
402
|
+
reader = sitk.ImageFileReader()
|
|
403
|
+
reader.SetFileName(str(path))
|
|
404
|
+
reader.ReadImageInformation() # Read geometry without loading voxel data.
|
|
405
|
+
if reader.GetDimension() != 3:
|
|
406
|
+
raise ValueError("Registration inputs must be 3D")
|
|
407
|
+
return ImageHeader(
|
|
408
|
+
origin=reader.GetOrigin(),
|
|
409
|
+
spacing=reader.GetSpacing(),
|
|
410
|
+
direction=reader.GetDirection(),
|
|
411
|
+
size=reader.GetSize(),
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
registration_dir, fixed_image, moving_image = map(Path, sys.argv[1:])
|
|
416
|
+
sidecar = make_syn_sidecar(
|
|
417
|
+
fixed_image_header=read_header(fixed_image),
|
|
418
|
+
moving_image_header=read_header(moving_image),
|
|
419
|
+
affine="ls_to_template_SyN_0GenericAffine.mat",
|
|
420
|
+
warp="ls_to_template_SyN_1Warp.nii.gz",
|
|
421
|
+
inverse_warp="ls_to_template_SyN_1InverseWarp.nii.gz",
|
|
422
|
+
)
|
|
423
|
+
text = dump_package(sidecar)
|
|
424
|
+
load_package(text) # Validate the serialized package.
|
|
425
|
+
destination = registration_dir / "ls_to_template_transform_information.json"
|
|
426
|
+
destination.write_text(text + "\n")
|
|
427
|
+
print(destination)
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Pass the transform directory, fixed image, and moving image in that order:
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
uv run python generate_registration_sidecar.py \
|
|
434
|
+
/path/to/SmartSPIM_750108_reg/ccf_Ex_639_Em_667 \
|
|
435
|
+
/path/to/fixed_template_used_by_ants.nii.gz \
|
|
436
|
+
/path/to/moving_histology_used_by_ants.nii.gz
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
The script reads only image headers. Transform filenames are relative to the
|
|
440
|
+
sidecar; rename raw ANTs outputs to the expected names. The schema requires a
|
|
441
|
+
forward-warp filename, but normal preprocessing needs only the affine and
|
|
442
|
+
inverse warp. The helper does not verify transform files.
|
|
443
|
+
|
|
444
|
+
Generate the JSON beside the transforms before uploading the asset;
|
|
445
|
+
Code Ocean's `/data` mounts are read-only.
|
|
446
|
+
|
|
447
|
+
### Separate template-to-CCF registration
|
|
448
|
+
|
|
449
|
+
A brain registered to a template other than the SmartSPIM LCA template (an
|
|
450
|
+
iDISCO template, say) needs that template's CCF registration. Set the optional
|
|
451
|
+
`template_to_ccf_asset` column to its directory relative to `data_root`, one
|
|
452
|
+
path per brain like `registration_asset`:
|
|
453
|
+
|
|
454
|
+
```csv
|
|
455
|
+
mouseid,sorted_recording,probe_file,histology_track_id,ephys_collection,registration_asset,template_to_ccf_asset
|
|
456
|
+
750107,recording_sorted,probeA,A0001,ProbeA,idisco_reg/750107,idisco_template_2026-10/template_to_ccf
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
The directory must contain `syn_0GenericAffine.mat` and
|
|
460
|
+
`syn_1InverseWarp.nii.gz`, ANTs SyN outputs with CCF fixed and the template
|
|
461
|
+
moving; `emit_qc=True` also needs `syn_1Warp.nii.gz`. They replace the
|
|
462
|
+
pipeline's `spim_template_to_ccf_syn_*_25` transforms in the probe and QC
|
|
463
|
+
chains, and the datapackage refers to them under the `template_to_ccf` asset,
|
|
464
|
+
named after the directory's first component under `data_root`.
|
|
465
|
+
|
|
466
|
+
The column requires a `registration_asset` with a sidecar, whose `fixed_domain`
|
|
467
|
+
is checked against this template. If the directory ships its own sidecar
|
|
468
|
+
(`template_to_ccf_transform_information.json` or `transform_information.json`),
|
|
469
|
+
the registration's `fixed_domain` must match its `moving_domain`. Without one,
|
|
470
|
+
the registration's `fixed_domain` must *not* match the SmartSPIM LCA template;
|
|
471
|
+
to replace the LCA template's own CCF registration, ship the sidecar.
|
|
295
472
|
|
|
296
473
|
### Reference volumes
|
|
297
474
|
|
|
@@ -368,9 +545,13 @@ results_root/
|
|
|
368
545
|
+-- band_corr/ # Full matrices + row_channels.json
|
|
369
546
|
```
|
|
370
547
|
|
|
371
|
-
The `datapackage.json` file
|
|
372
|
-
|
|
373
|
-
|
|
548
|
+
The `datapackage.json` file describes the mouse, recordings, ephys collections,
|
|
549
|
+
transform chain, histology, channel tables, and track mappings. It references
|
|
550
|
+
each ephys directory; individual spike/QC files and `band_corr/` contents are
|
|
551
|
+
loaded by convention rather than enumerated in the JSON. See
|
|
552
|
+
[the datapackage contract](docs/external_asset_references.md) for asset
|
|
553
|
+
descriptions versus runtime location resolution, Code Ocean/desktop examples,
|
|
554
|
+
shank joins, and validation limits. The model can be loaded back with:
|
|
374
555
|
|
|
375
556
|
```python
|
|
376
557
|
from aind_ibl_ephys_alignment_preprocessing.datapackage import load_datapackage
|
|
@@ -395,7 +576,9 @@ The pipeline performs the following steps:
|
|
|
395
576
|
`xyz_picks.json` files for the alignment GUI.
|
|
396
577
|
5. **Ephys extraction** (optional) -- Convert spike-sorted data into IBL ALF
|
|
397
578
|
format.
|
|
398
|
-
6. **Manifest generation** -- Write `datapackage.json`
|
|
579
|
+
6. **Manifest generation** -- Write `datapackage.json` describing explicit
|
|
580
|
+
references and ephys collection directories; preserve their conventional
|
|
581
|
+
contents, including QC files not individually listed in the JSON.
|
|
399
582
|
|
|
400
583
|
## Adapting to your own data
|
|
401
584
|
|
|
@@ -423,31 +606,8 @@ origin at bregma, in meters.
|
|
|
423
606
|
|
|
424
607
|
## Development
|
|
425
608
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
uv sync
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
Please test your changes using the full linting and testing suite:
|
|
432
|
-
|
|
433
|
-
```bash
|
|
434
|
-
./scripts/run_linters_and_checks.sh -c
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
Or run individual commands:
|
|
438
|
-
```bash
|
|
439
|
-
uv run --frozen ruff format # Code formatting
|
|
440
|
-
uv run --frozen ruff check # Linting
|
|
441
|
-
uv run --frozen mypy # Type checking
|
|
442
|
-
uv run --frozen interrogate -v src # Documentation coverage
|
|
443
|
-
uv run --frozen codespell --check-filenames # Spell checking
|
|
444
|
-
uv run --frozen pytest --cov aind_ibl_ephys_alignment_preprocessing # Tests with coverage
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
### Documentation
|
|
448
|
-
```bash
|
|
449
|
-
sphinx-build -b html docs/source/ docs/build/html
|
|
450
|
-
```
|
|
609
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for developer setup, checks, and
|
|
610
|
+
repository conventions. Coding agents should also read [AGENTS.md](AGENTS.md).
|
|
451
611
|
|
|
452
612
|
## License
|
|
453
613
|
|
|
@@ -227,7 +227,8 @@ before a column existed stays valid.
|
|
|
227
227
|
| `probe_name` | *legacy* | Alias for `ephys_collection`. |
|
|
228
228
|
| `probe_shank` | *legacy* | Alias for both `histology_shank` and `ephys_shank`. |
|
|
229
229
|
| `surface_finding` | *null* | Path (relative to `data_root`) to a surface-finding file. |
|
|
230
|
-
| `registration_asset` | *null* | Path
|
|
230
|
+
| `registration_asset` | *null* | Path relative to `data_root` to a replacement registration directory, e.g. `SmartSPIM_750108_reg/ccf_Ex_639_Em_667`. One value per brain; all nonblank rows must agree. See [Separate registration asset](#separate-registration-asset) for its contents and coordinate requirements. |
|
|
231
|
+
| `template_to_ccf_asset` | *null* | Path relative to `data_root` to the template-to-CCF registration of the template `registration_asset` was registered to, when that is not the SmartSPIM LCA template. One value per brain, like `registration_asset`. See [Separate template-to-CCF registration](#separate-template-to-ccf-registration). |
|
|
231
232
|
|
|
232
233
|
**Constraints:**
|
|
233
234
|
- All rows must have the same `mouseid`.
|
|
@@ -252,6 +253,52 @@ mouse001,2024-06-01_rec_sorted,track_annotations_probeB_shank1,B0001,probeB,Prob
|
|
|
252
253
|
mouse001,2024-06-01_rec_sorted,track_annotations_quad_shank3,Q0001,quad0,ProbeD,3,0
|
|
253
254
|
```
|
|
254
255
|
|
|
256
|
+
#### Building a manifest from a mapping
|
|
257
|
+
|
|
258
|
+
Most of a manifest repeats or follows from two choices: which sorted recording each session uses,
|
|
259
|
+
and which stream each annotated track was recorded on. `aind-ibl-build-manifest` takes only those,
|
|
260
|
+
in a TOML file, and derives the rest. Track names are never parsed, because annotators follow no
|
|
261
|
+
naming convention.
|
|
262
|
+
|
|
263
|
+
```toml
|
|
264
|
+
mouseid = "837772"
|
|
265
|
+
annotation = "837772-probe-annotations-CK-2026-09-29.json" # relative to this file
|
|
266
|
+
# registration_asset = "..." # optional, per brain
|
|
267
|
+
# template_to_ccf_asset = "..." # optional, per brain
|
|
268
|
+
|
|
269
|
+
[[session]]
|
|
270
|
+
sorted_recording = "ecephys_837772_2026-06-27_14-08-21_sorted_2026-08-27_18-59-49"
|
|
271
|
+
# surface_finding = "..." # optional
|
|
272
|
+
|
|
273
|
+
[session.tracks]
|
|
274
|
+
"732_MD_1" = "46101-1" # one shank of a split quad-base probe
|
|
275
|
+
"733_BLA" = "46810" # a single-stream probe
|
|
276
|
+
"740_PL" = { stream = "45883", shank = 1 } # one shank of a single-stream multi-shank probe; the first shank is 1
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
aind-ibl-build-manifest 837772.toml -o manifest_837772.csv [--data-root /data]
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
A stream is the collection parsed from the sort's `postprocessed/` analyzer names. They are listed
|
|
284
|
+
from a copy mounted under `--data-root`, or else unsigned from that sort's prefix in
|
|
285
|
+
`aind-open-data`. How the columns are derived:
|
|
286
|
+
|
|
287
|
+
- `probe_file` is the annotation file's name without its extension.
|
|
288
|
+
- **Split quad-base probe:** a stream `<probe>-<N>`, when the sort also holds another
|
|
289
|
+
`<probe>-<M>`, gets `logical_probe = <probe>`, `histology_shank = N - 1` and `ephys_shank = 0`.
|
|
290
|
+
- **Any other stream** is its own `logical_probe`. Its shanks stay blank, or both take the given
|
|
291
|
+
shank's index.
|
|
292
|
+
|
|
293
|
+
The build writes nothing if any of these fail, and it reports every failure:
|
|
294
|
+
- every stream in each sort has a track, and every assigned stream is in its sort;
|
|
295
|
+
- every track is a layer of the annotation file with at least two points;
|
|
296
|
+
- no track is assigned twice;
|
|
297
|
+
- a split stream has exactly one track, and the tracks sharing any other stream have distinct
|
|
298
|
+
shanks.
|
|
299
|
+
|
|
300
|
+
Annotated layers left out of the mapping are printed as notes, so a missed track gets noticed.
|
|
301
|
+
|
|
255
302
|
### Neuroglancer JSON
|
|
256
303
|
|
|
257
304
|
A Neuroglancer state JSON file that contains image source URIs pointing to the
|
|
@@ -262,7 +309,136 @@ and any additional channels.
|
|
|
262
309
|
The asset directory must contain:
|
|
263
310
|
- `image_tile_fusing/OMEZarr/<channel>.zarr/` -- fused OME-Zarr volumes
|
|
264
311
|
- `image_atlas_alignment/<registration_channel_stem>/` -- ANTs registration
|
|
265
|
-
outputs: the light-sheet to template affine and inverse warp
|
|
312
|
+
outputs: the light-sheet to template affine and inverse warp (or supply a
|
|
313
|
+
separate registration asset as described below)
|
|
314
|
+
|
|
315
|
+
### Separate registration asset
|
|
316
|
+
|
|
317
|
+
Set the manifest's optional `registration_asset` column to the transform
|
|
318
|
+
directory relative to `data_root`:
|
|
319
|
+
|
|
320
|
+
```csv
|
|
321
|
+
mouseid,sorted_recording,probe_file,histology_track_id,ephys_collection,registration_asset
|
|
322
|
+
750108,recording_sorted,probeA,A0001,ProbeA,SmartSPIM_750108_reg/ccf_Ex_639_Em_667
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Use one path per brain; conflicting nonblank values fail. An absent or blank
|
|
326
|
+
column uses the stitched asset's registration.
|
|
327
|
+
|
|
328
|
+
The directory must contain `ls_to_template_SyN_0GenericAffine.mat`,
|
|
329
|
+
`ls_to_template_SyN_1InverseWarp.nii.gz` and a geometry sidecar (below): ANTs
|
|
330
|
+
SyN outputs registering this brain's selected channel to the SmartSPIM LCA
|
|
331
|
+
template, or to another template whose CCF registration
|
|
332
|
+
`template_to_ccf_asset` (below) supplies.
|
|
333
|
+
|
|
334
|
+
The final directory name selects the channel after stripping a leading
|
|
335
|
+
`ccf_`. For this example, the stitched asset must contain
|
|
336
|
+
`image_tile_fusing/OMEZarr/Ex_639_Em_667.zarr/`. Images and metadata come
|
|
337
|
+
from the stitched asset; the override needs only transforms and their sidecar.
|
|
338
|
+
|
|
339
|
+
Every separate registration needs a geometry sidecar beside the transforms;
|
|
340
|
+
a directory without one fails. Preprocessing checks
|
|
341
|
+
`ls_to_template_transform_information.json`, then `transform_information.json`.
|
|
342
|
+
Its `moving_domain` must describe the actual registration input in LPS
|
|
343
|
+
millimeters and match the selected volume's native or pipeline-anchored frame.
|
|
344
|
+
Its `fixed_domain` must match the template the template-to-CCF chain starts
|
|
345
|
+
from: the SmartSPIM LCA template unless `template_to_ccf_asset` is set. Missing
|
|
346
|
+
or incompatible domains fail, since a wrong frame or template still puts the
|
|
347
|
+
probes somewhere plausible.
|
|
348
|
+
|
|
349
|
+
**QC:** Additional-channel CCF volumes (`emit_qc=True`) also need
|
|
350
|
+
`ls_to_template_SyN_1Warp.nii.gz` in the override directory; without it the
|
|
351
|
+
QC warp fails rather than falling back to the stitched asset's registration.
|
|
352
|
+
|
|
353
|
+
#### Generate the sidecar from ANTs outputs
|
|
354
|
+
|
|
355
|
+
Use the actual fixed template and moving histology images passed to ANTs,
|
|
356
|
+
including any preprocessing of their geometry. Transform files alone cannot
|
|
357
|
+
recover these domains. Headers must be 3D, axis-aligned, and in millimeters.
|
|
358
|
+
|
|
359
|
+
Run `uv sync` in the preprocessing library checkout, then save this as
|
|
360
|
+
`generate_registration_sidecar.py`:
|
|
361
|
+
|
|
362
|
+
```python
|
|
363
|
+
import sys
|
|
364
|
+
from pathlib import Path
|
|
365
|
+
|
|
366
|
+
import SimpleITK as sitk
|
|
367
|
+
from aind_ants_transform_sidecar import dump_package, load_package
|
|
368
|
+
from aind_registration_utils.domains import ImageHeader, make_syn_sidecar
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def read_header(path):
|
|
372
|
+
reader = sitk.ImageFileReader()
|
|
373
|
+
reader.SetFileName(str(path))
|
|
374
|
+
reader.ReadImageInformation() # Read geometry without loading voxel data.
|
|
375
|
+
if reader.GetDimension() != 3:
|
|
376
|
+
raise ValueError("Registration inputs must be 3D")
|
|
377
|
+
return ImageHeader(
|
|
378
|
+
origin=reader.GetOrigin(),
|
|
379
|
+
spacing=reader.GetSpacing(),
|
|
380
|
+
direction=reader.GetDirection(),
|
|
381
|
+
size=reader.GetSize(),
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
registration_dir, fixed_image, moving_image = map(Path, sys.argv[1:])
|
|
386
|
+
sidecar = make_syn_sidecar(
|
|
387
|
+
fixed_image_header=read_header(fixed_image),
|
|
388
|
+
moving_image_header=read_header(moving_image),
|
|
389
|
+
affine="ls_to_template_SyN_0GenericAffine.mat",
|
|
390
|
+
warp="ls_to_template_SyN_1Warp.nii.gz",
|
|
391
|
+
inverse_warp="ls_to_template_SyN_1InverseWarp.nii.gz",
|
|
392
|
+
)
|
|
393
|
+
text = dump_package(sidecar)
|
|
394
|
+
load_package(text) # Validate the serialized package.
|
|
395
|
+
destination = registration_dir / "ls_to_template_transform_information.json"
|
|
396
|
+
destination.write_text(text + "\n")
|
|
397
|
+
print(destination)
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Pass the transform directory, fixed image, and moving image in that order:
|
|
401
|
+
|
|
402
|
+
```bash
|
|
403
|
+
uv run python generate_registration_sidecar.py \
|
|
404
|
+
/path/to/SmartSPIM_750108_reg/ccf_Ex_639_Em_667 \
|
|
405
|
+
/path/to/fixed_template_used_by_ants.nii.gz \
|
|
406
|
+
/path/to/moving_histology_used_by_ants.nii.gz
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
The script reads only image headers. Transform filenames are relative to the
|
|
410
|
+
sidecar; rename raw ANTs outputs to the expected names. The schema requires a
|
|
411
|
+
forward-warp filename, but normal preprocessing needs only the affine and
|
|
412
|
+
inverse warp. The helper does not verify transform files.
|
|
413
|
+
|
|
414
|
+
Generate the JSON beside the transforms before uploading the asset;
|
|
415
|
+
Code Ocean's `/data` mounts are read-only.
|
|
416
|
+
|
|
417
|
+
### Separate template-to-CCF registration
|
|
418
|
+
|
|
419
|
+
A brain registered to a template other than the SmartSPIM LCA template (an
|
|
420
|
+
iDISCO template, say) needs that template's CCF registration. Set the optional
|
|
421
|
+
`template_to_ccf_asset` column to its directory relative to `data_root`, one
|
|
422
|
+
path per brain like `registration_asset`:
|
|
423
|
+
|
|
424
|
+
```csv
|
|
425
|
+
mouseid,sorted_recording,probe_file,histology_track_id,ephys_collection,registration_asset,template_to_ccf_asset
|
|
426
|
+
750107,recording_sorted,probeA,A0001,ProbeA,idisco_reg/750107,idisco_template_2026-10/template_to_ccf
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
The directory must contain `syn_0GenericAffine.mat` and
|
|
430
|
+
`syn_1InverseWarp.nii.gz`, ANTs SyN outputs with CCF fixed and the template
|
|
431
|
+
moving; `emit_qc=True` also needs `syn_1Warp.nii.gz`. They replace the
|
|
432
|
+
pipeline's `spim_template_to_ccf_syn_*_25` transforms in the probe and QC
|
|
433
|
+
chains, and the datapackage refers to them under the `template_to_ccf` asset,
|
|
434
|
+
named after the directory's first component under `data_root`.
|
|
435
|
+
|
|
436
|
+
The column requires a `registration_asset` with a sidecar, whose `fixed_domain`
|
|
437
|
+
is checked against this template. If the directory ships its own sidecar
|
|
438
|
+
(`template_to_ccf_transform_information.json` or `transform_information.json`),
|
|
439
|
+
the registration's `fixed_domain` must match its `moving_domain`. Without one,
|
|
440
|
+
the registration's `fixed_domain` must *not* match the SmartSPIM LCA template;
|
|
441
|
+
to replace the LCA template's own CCF registration, ship the sidecar.
|
|
266
442
|
|
|
267
443
|
### Reference volumes
|
|
268
444
|
|
|
@@ -339,9 +515,13 @@ results_root/
|
|
|
339
515
|
+-- band_corr/ # Full matrices + row_channels.json
|
|
340
516
|
```
|
|
341
517
|
|
|
342
|
-
The `datapackage.json` file
|
|
343
|
-
|
|
344
|
-
|
|
518
|
+
The `datapackage.json` file describes the mouse, recordings, ephys collections,
|
|
519
|
+
transform chain, histology, channel tables, and track mappings. It references
|
|
520
|
+
each ephys directory; individual spike/QC files and `band_corr/` contents are
|
|
521
|
+
loaded by convention rather than enumerated in the JSON. See
|
|
522
|
+
[the datapackage contract](docs/external_asset_references.md) for asset
|
|
523
|
+
descriptions versus runtime location resolution, Code Ocean/desktop examples,
|
|
524
|
+
shank joins, and validation limits. The model can be loaded back with:
|
|
345
525
|
|
|
346
526
|
```python
|
|
347
527
|
from aind_ibl_ephys_alignment_preprocessing.datapackage import load_datapackage
|
|
@@ -366,7 +546,9 @@ The pipeline performs the following steps:
|
|
|
366
546
|
`xyz_picks.json` files for the alignment GUI.
|
|
367
547
|
5. **Ephys extraction** (optional) -- Convert spike-sorted data into IBL ALF
|
|
368
548
|
format.
|
|
369
|
-
6. **Manifest generation** -- Write `datapackage.json`
|
|
549
|
+
6. **Manifest generation** -- Write `datapackage.json` describing explicit
|
|
550
|
+
references and ephys collection directories; preserve their conventional
|
|
551
|
+
contents, including QC files not individually listed in the JSON.
|
|
370
552
|
|
|
371
553
|
## Adapting to your own data
|
|
372
554
|
|
|
@@ -394,31 +576,8 @@ origin at bregma, in meters.
|
|
|
394
576
|
|
|
395
577
|
## Development
|
|
396
578
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
uv sync
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
Please test your changes using the full linting and testing suite:
|
|
403
|
-
|
|
404
|
-
```bash
|
|
405
|
-
./scripts/run_linters_and_checks.sh -c
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
Or run individual commands:
|
|
409
|
-
```bash
|
|
410
|
-
uv run --frozen ruff format # Code formatting
|
|
411
|
-
uv run --frozen ruff check # Linting
|
|
412
|
-
uv run --frozen mypy # Type checking
|
|
413
|
-
uv run --frozen interrogate -v src # Documentation coverage
|
|
414
|
-
uv run --frozen codespell --check-filenames # Spell checking
|
|
415
|
-
uv run --frozen pytest --cov aind_ibl_ephys_alignment_preprocessing # Tests with coverage
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
### Documentation
|
|
419
|
-
```bash
|
|
420
|
-
sphinx-build -b html docs/source/ docs/build/html
|
|
421
|
-
```
|
|
579
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for developer setup, checks, and
|
|
580
|
+
repository conventions. Coding agents should also read [AGENTS.md](AGENTS.md).
|
|
422
581
|
|
|
423
582
|
## License
|
|
424
583
|
|