miss-alignment 0.1.4__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.
- miss_alignment-0.1.4/.github/ISSUE_TEMPLATE.md +15 -0
- miss_alignment-0.1.4/.github/TEST_FAIL_TEMPLATE.md +12 -0
- miss_alignment-0.1.4/.github/dependabot.yml +10 -0
- miss_alignment-0.1.4/.github/workflows/ci.yml +90 -0
- miss_alignment-0.1.4/.gitignore +114 -0
- miss_alignment-0.1.4/.pre-commit-config.yaml +15 -0
- miss_alignment-0.1.4/CLAUDE.md +346 -0
- miss_alignment-0.1.4/LICENSE +28 -0
- miss_alignment-0.1.4/PKG-INFO +90 -0
- miss_alignment-0.1.4/README.md +40 -0
- miss_alignment-0.1.4/docs/run_in_warptools.md +19 -0
- miss_alignment-0.1.4/examples/correlate_reconstruction.py +56 -0
- miss_alignment-0.1.4/examples/etomo_to_warp.py +291 -0
- miss_alignment-0.1.4/examples/plot_data.py +211 -0
- miss_alignment-0.1.4/examples/plot_shift_generation.py +119 -0
- miss_alignment-0.1.4/examples/postproc.py +71 -0
- miss_alignment-0.1.4/examples/profile_create_pool_reconstruction.py +41 -0
- miss_alignment-0.1.4/examples/shrec/_raw_shrec_to_pickles.py +124 -0
- miss_alignment-0.1.4/examples/shrec/at2-alignment.json +1282 -0
- miss_alignment-0.1.4/examples/shrec/at3-alignment.json +1154 -0
- miss_alignment-0.1.4/examples/shrec/compare_to_ground_truth.py +291 -0
- miss_alignment-0.1.4/examples/shrec/compare_to_ground_truth_aretomo.py +508 -0
- miss_alignment-0.1.4/examples/shrec/how-to-run.md +102 -0
- miss_alignment-0.1.4/examples/shrec/iterations/iter0.json +1282 -0
- miss_alignment-0.1.4/examples/shrec/iterations/iter1.json +1282 -0
- miss_alignment-0.1.4/examples/shrec/iterations/iter2.json +1282 -0
- miss_alignment-0.1.4/examples/shrec/iterations/iter3.json +1282 -0
- miss_alignment-0.1.4/examples/shrec/iterations/iter4.json +1282 -0
- miss_alignment-0.1.4/examples/shrec/iterations/iter5.json +1282 -0
- miss_alignment-0.1.4/examples/shrec/iterations/iter6.json +1282 -0
- miss_alignment-0.1.4/examples/shrec/plot_alignment_comparison.py +140 -0
- miss_alignment-0.1.4/examples/shrec/preproc.py +181 -0
- miss_alignment-0.1.4/examples/shrec/running_aretomo.md +70 -0
- miss_alignment-0.1.4/examples/shrec/shrec_experiment_downsample_errors_per_ts.json +1282 -0
- miss_alignment-0.1.4/examples/shrec/shrec_experiment_downsample_result_summary.txt +129 -0
- miss_alignment-0.1.4/paper/manuscript.md +28 -0
- miss_alignment-0.1.4/paper/notebooks/illustrate_shifts.ipynb +579 -0
- miss_alignment-0.1.4/paper/notebooks/shift_illustration_combined.svg +1161 -0
- miss_alignment-0.1.4/paper/notebooks/shift_illustration_fractures.svg +1225 -0
- miss_alignment-0.1.4/paper/notebooks/shift_illustration_jitter.svg +1088 -0
- miss_alignment-0.1.4/paper/notebooks/shift_illustration_no_shifts.svg +1167 -0
- miss_alignment-0.1.4/paper/notebooks/shift_illustration_outliers.svg +1168 -0
- miss_alignment-0.1.4/paper/notebooks/shift_illustration_trajectory.svg +1178 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/ablation_experiment.ipynb +161 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/alignment_progression.gif +0 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/aretomo1_alignment/model_0.aln +65 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/aretomo1_alignment/model_1.aln +65 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/aretomo1_alignment/model_2.aln +65 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/aretomo1_alignment/model_3.aln +65 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/aretomo1_alignment/model_4.aln +65 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/aretomo1_alignment/model_5.aln +65 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/aretomo1_alignment/model_6.aln +65 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/aretomo1_alignment/model_7.aln +65 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/aretomo1_alignment/model_8.aln +65 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/aretomo1_alignment/model_9.aln +65 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/model_2_baseline_xy.svg +44 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/model_2_baseline_xz.svg +44 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/model_2_baseline_yz.svg +44 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/model_2_missalignment_xy.svg +44 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/model_2_missalignment_xz.svg +44 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/model_2_missalignment_yz.svg +44 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/shrec_benchmark_per_tilt_error.svg +1331 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/shrec_benchmark_progression_combined_error.svg +1555 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/utils.py +32 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/visualize_iterations.ipynb +760 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/visualize_reconstruction_gif.ipynb +438 -0
- miss_alignment-0.1.4/paper/notebooks/shrec_eval/visualize_reconstruction_slices.ipynb +461 -0
- miss_alignment-0.1.4/paper/notebooks/triplet_clone.mrc +0 -0
- miss_alignment-0.1.4/paper/notebooks/triplet_degraded.mrc +0 -0
- miss_alignment-0.1.4/paper/notebooks/triplet_perfect.mrc +0 -0
- miss_alignment-0.1.4/paper/notebooks/view_triplet.py +12 -0
- miss_alignment-0.1.4/pyproject.toml +128 -0
- miss_alignment-0.1.4/src/miss_alignment/__init__.py +19 -0
- miss_alignment-0.1.4/src/miss_alignment/_cli.py +13 -0
- miss_alignment-0.1.4/src/miss_alignment/alignment/__init__.py +4 -0
- miss_alignment-0.1.4/src/miss_alignment/alignment/correlation.py +112 -0
- miss_alignment-0.1.4/src/miss_alignment/alignment/optimize_global.py +519 -0
- miss_alignment-0.1.4/src/miss_alignment/alignment/optimize_iterative.py +248 -0
- miss_alignment-0.1.4/src/miss_alignment/alignment/optimize_spline.py +404 -0
- miss_alignment-0.1.4/src/miss_alignment/alignment/parallel.py +158 -0
- miss_alignment-0.1.4/src/miss_alignment/alignment/statistics.py +245 -0
- miss_alignment-0.1.4/src/miss_alignment/alignment/tilt_series.py +266 -0
- miss_alignment-0.1.4/src/miss_alignment/alignment/utils.py +32 -0
- miss_alignment-0.1.4/src/miss_alignment/config_template.yaml +51 -0
- miss_alignment-0.1.4/src/miss_alignment/data/__init__.py +5 -0
- miss_alignment-0.1.4/src/miss_alignment/data/_augmentation.py +110 -0
- miss_alignment-0.1.4/src/miss_alignment/data/_reconstruction_worker.py +422 -0
- miss_alignment-0.1.4/src/miss_alignment/data/io.py +210 -0
- miss_alignment-0.1.4/src/miss_alignment/data/shift_generation.py +353 -0
- miss_alignment-0.1.4/src/miss_alignment/data/training_datamodule.py +301 -0
- miss_alignment-0.1.4/src/miss_alignment/data/training_dataset.py +150 -0
- miss_alignment-0.1.4/src/miss_alignment/gradcam/__init__.py +0 -0
- miss_alignment-0.1.4/src/miss_alignment/gradcam/gradcam.py +123 -0
- miss_alignment-0.1.4/src/miss_alignment/models/__init__.py +31 -0
- miss_alignment-0.1.4/src/miss_alignment/models/_compact.py +364 -0
- miss_alignment-0.1.4/src/miss_alignment/models/_resnet.py +209 -0
- miss_alignment-0.1.4/src/miss_alignment/models/models.py +523 -0
- miss_alignment-0.1.4/src/miss_alignment/prepare_stacks.py +167 -0
- miss_alignment-0.1.4/src/miss_alignment/preprocessing.py +151 -0
- miss_alignment-0.1.4/src/miss_alignment/py.typed +5 -0
- miss_alignment-0.1.4/src/miss_alignment/train.py +337 -0
- miss_alignment-0.1.4/src/miss_alignment/utils.py +51 -0
- miss_alignment-0.1.4/tests/alignment/test_optimize_global.py +193 -0
- miss_alignment-0.1.4/tests/alignment/test_statistics.py +244 -0
- miss_alignment-0.1.4/tests/alignment/test_tilt_series.py +330 -0
- miss_alignment-0.1.4/tests/data/test_augmentation.py +386 -0
- miss_alignment-0.1.4/tests/data/test_io.py +215 -0
- miss_alignment-0.1.4/tests/data/test_pool_dataset.py +278 -0
- miss_alignment-0.1.4/tests/data/test_reconstruction_worker.py +779 -0
- miss_alignment-0.1.4/tests/data/test_shift_generation.py +553 -0
- miss_alignment-0.1.4/tests/models/test_models.py +1 -0
- miss_alignment-0.1.4/tests/models/test_resnet.py +15 -0
- miss_alignment-0.1.4/tests/test_miss_alignment.py +2 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
* miss-alignment version:
|
|
2
|
+
* Python version:
|
|
3
|
+
* Operating System:
|
|
4
|
+
|
|
5
|
+
### Description
|
|
6
|
+
|
|
7
|
+
Describe what you were trying to get done.
|
|
8
|
+
Tell us what happened, what went wrong, and what you expected to happen.
|
|
9
|
+
|
|
10
|
+
### What I Did
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Paste the command(s) you ran and the output.
|
|
14
|
+
If there was a crash, please include the traceback here.
|
|
15
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "{{ env.TITLE }}"
|
|
3
|
+
labels: [bug]
|
|
4
|
+
---
|
|
5
|
+
The {{ workflow }} workflow failed on {{ date | date("YYYY-MM-DD HH:mm") }} UTC
|
|
6
|
+
|
|
7
|
+
The most recent failing test was on {{ env.PLATFORM }} py{{ env.PYTHON }}
|
|
8
|
+
with commit: {{ sha }}
|
|
9
|
+
|
|
10
|
+
Full run: https://github.com/{{ repo }}/actions/runs/{{ env.RUN_ID }}
|
|
11
|
+
|
|
12
|
+
(This post will be updated if another test fails, as long as this issue remains open.)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
2
|
+
|
|
3
|
+
version: 2
|
|
4
|
+
updates:
|
|
5
|
+
- package-ecosystem: "github-actions"
|
|
6
|
+
directory: "/"
|
|
7
|
+
schedule:
|
|
8
|
+
interval: "weekly"
|
|
9
|
+
commit-message:
|
|
10
|
+
prefix: "ci(dependabot):"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
tags:
|
|
8
|
+
- "v*"
|
|
9
|
+
pull_request:
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# cancel in-progress runs that use the same workflow and branch
|
|
14
|
+
concurrency:
|
|
15
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
16
|
+
cancel-in-progress: true
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
test:
|
|
20
|
+
name: ${{ matrix.platform }} (${{ matrix.python-version }})
|
|
21
|
+
runs-on: ${{ matrix.platform }}
|
|
22
|
+
strategy:
|
|
23
|
+
fail-fast: false
|
|
24
|
+
matrix:
|
|
25
|
+
python-version: ["3.10", "3.13"]
|
|
26
|
+
platform: [ubuntu-latest]
|
|
27
|
+
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v6
|
|
30
|
+
|
|
31
|
+
- name: 🐍 Set up Python ${{ matrix.python-version }}
|
|
32
|
+
uses: actions/setup-python@v6
|
|
33
|
+
with:
|
|
34
|
+
python-version: ${{ matrix.python-version }}
|
|
35
|
+
cache-dependency-path: "pyproject.toml"
|
|
36
|
+
cache: "pip"
|
|
37
|
+
|
|
38
|
+
- name: Install PyTorch
|
|
39
|
+
run: |
|
|
40
|
+
python -m pip install -U pip
|
|
41
|
+
python -m pip install torch==2.6.0 --index-url https://download.pytorch.org/whl/cpu
|
|
42
|
+
|
|
43
|
+
- name: Install torch-projectors (CPU)
|
|
44
|
+
run: |
|
|
45
|
+
python -m pip install torch-projectors --index-url https://warpem.github.io/torch-projectors/cpu/simple/
|
|
46
|
+
|
|
47
|
+
- name: Install package
|
|
48
|
+
run: python -m pip install .[test]
|
|
49
|
+
|
|
50
|
+
- name: 🧪 Run Tests
|
|
51
|
+
run: pytest --color=yes --cov --cov-report=xml --cov-report=term-missing
|
|
52
|
+
|
|
53
|
+
- name: Coverage
|
|
54
|
+
uses: codecov/codecov-action@v6
|
|
55
|
+
|
|
56
|
+
deploy:
|
|
57
|
+
name: Deploy
|
|
58
|
+
needs: test
|
|
59
|
+
if: success() && startsWith(github.ref, 'refs/tags/')
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
|
|
62
|
+
permissions:
|
|
63
|
+
# IMPORTANT: this permission is mandatory for trusted publishing on PyPi
|
|
64
|
+
# see https://docs.pypi.org/trusted-publishers/
|
|
65
|
+
id-token: write
|
|
66
|
+
# This permission allows writing releases
|
|
67
|
+
contents: write
|
|
68
|
+
|
|
69
|
+
steps:
|
|
70
|
+
- uses: actions/checkout@v6
|
|
71
|
+
with:
|
|
72
|
+
fetch-depth: 0
|
|
73
|
+
|
|
74
|
+
- name: 🐍 Set up Python
|
|
75
|
+
uses: actions/setup-python@v6
|
|
76
|
+
with:
|
|
77
|
+
python-version: "3.x"
|
|
78
|
+
|
|
79
|
+
- name: 👷 Build
|
|
80
|
+
run: |
|
|
81
|
+
python -m pip install build
|
|
82
|
+
python -m build
|
|
83
|
+
|
|
84
|
+
- name: 🚢 Publish to PyPI
|
|
85
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
86
|
+
|
|
87
|
+
- uses: softprops/action-gh-release@v3
|
|
88
|
+
with:
|
|
89
|
+
generate_release_notes: true
|
|
90
|
+
files: './dist/*'
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
env/
|
|
12
|
+
build/
|
|
13
|
+
develop-eggs/
|
|
14
|
+
dist/
|
|
15
|
+
downloads/
|
|
16
|
+
eggs/
|
|
17
|
+
.eggs/
|
|
18
|
+
lib/
|
|
19
|
+
lib64/
|
|
20
|
+
parts/
|
|
21
|
+
sdist/
|
|
22
|
+
var/
|
|
23
|
+
wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
|
|
28
|
+
.DS_Store
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
# Usually these files are written by a python script from a template
|
|
32
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
33
|
+
*.manifest
|
|
34
|
+
*.spec
|
|
35
|
+
|
|
36
|
+
# Installer logs
|
|
37
|
+
pip-log.txt
|
|
38
|
+
pip-delete-this-directory.txt
|
|
39
|
+
|
|
40
|
+
# Unit test / coverage reports
|
|
41
|
+
htmlcov/
|
|
42
|
+
.tox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
.hypothesis/
|
|
50
|
+
.pytest_cache/
|
|
51
|
+
|
|
52
|
+
# Translations
|
|
53
|
+
*.mo
|
|
54
|
+
*.pot
|
|
55
|
+
|
|
56
|
+
# Django stuff:
|
|
57
|
+
*.log
|
|
58
|
+
local_settings.py
|
|
59
|
+
|
|
60
|
+
# Flask stuff:
|
|
61
|
+
instance/
|
|
62
|
+
.webassets-cache
|
|
63
|
+
|
|
64
|
+
# Scrapy stuff:
|
|
65
|
+
.scrapy
|
|
66
|
+
|
|
67
|
+
# Sphinx documentation
|
|
68
|
+
docs/_build/
|
|
69
|
+
|
|
70
|
+
# PyBuilder
|
|
71
|
+
target/
|
|
72
|
+
|
|
73
|
+
# Jupyter Notebook
|
|
74
|
+
.ipynb_checkpoints
|
|
75
|
+
|
|
76
|
+
# pyenv
|
|
77
|
+
.python-version
|
|
78
|
+
|
|
79
|
+
# celery beat schedule file
|
|
80
|
+
celerybeat-schedule
|
|
81
|
+
|
|
82
|
+
# SageMath parsed files
|
|
83
|
+
*.sage.py
|
|
84
|
+
|
|
85
|
+
# dotenv
|
|
86
|
+
.env
|
|
87
|
+
|
|
88
|
+
# virtualenv
|
|
89
|
+
.venv
|
|
90
|
+
venv/
|
|
91
|
+
ENV/
|
|
92
|
+
|
|
93
|
+
# Spyder project settings
|
|
94
|
+
.spyderproject
|
|
95
|
+
.spyproject
|
|
96
|
+
|
|
97
|
+
# Rope project settings
|
|
98
|
+
.ropeproject
|
|
99
|
+
|
|
100
|
+
# mkdocs documentation
|
|
101
|
+
/site
|
|
102
|
+
|
|
103
|
+
# mypy
|
|
104
|
+
.mypy_cache/
|
|
105
|
+
|
|
106
|
+
# ruff
|
|
107
|
+
.ruff_cache/
|
|
108
|
+
|
|
109
|
+
# IDE settings
|
|
110
|
+
.vscode/
|
|
111
|
+
.idea/
|
|
112
|
+
|
|
113
|
+
# pydev copier answers
|
|
114
|
+
.copier-answers.yml
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
miss-alignment is a deep learning package for tilt-series alignment in cryo-electron tomography. It uses a contrastive learning approach with PyTorch and PyTorch Lightning to iteratively train 3D convolutional neural networks that optimize tilt-series alignment by minimizing shift artifacts in reconstructions.
|
|
8
|
+
|
|
9
|
+
**Key concept**: The system alternates between (1) training a model to score reconstruction quality and (2) using that model to optimize tilt-series alignment parameters through gradient descent.
|
|
10
|
+
|
|
11
|
+
### Scientific publication
|
|
12
|
+
|
|
13
|
+
This software is a research project. It will be written up in a manuscript. Therefore, consider for anything you write in the paper/ folder that it should adhere to scientific principles with an emphasis on clarity and simplicity.
|
|
14
|
+
|
|
15
|
+
## Environment Setup
|
|
16
|
+
|
|
17
|
+
This project has specific CUDA and PyTorch dependencies. Use the conda environment setup from README.md:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
conda create -n miss-alignment -c conda-forge python=3.11 cuda-toolkit=12.9 -y
|
|
21
|
+
conda activate miss-alignment
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Install with: `python -m pip install -e .[dev,test]`
|
|
25
|
+
|
|
26
|
+
## Common Commands
|
|
27
|
+
|
|
28
|
+
### Testing
|
|
29
|
+
```bash
|
|
30
|
+
# Run all tests with coverage
|
|
31
|
+
pytest --color=yes --cov --cov-report=xml --cov-report=term-missing
|
|
32
|
+
|
|
33
|
+
# Run tests in a specific directory
|
|
34
|
+
pytest tests/alignment/
|
|
35
|
+
|
|
36
|
+
# Run a single test file
|
|
37
|
+
pytest tests/data/test_training_dataset.py
|
|
38
|
+
|
|
39
|
+
# Run a specific test function
|
|
40
|
+
pytest tests/test_miss_alignment.py::test_something
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Linting
|
|
44
|
+
```bash
|
|
45
|
+
# Run ruff linter with auto-fix
|
|
46
|
+
ruff check --fix
|
|
47
|
+
|
|
48
|
+
# Run ruff formatter
|
|
49
|
+
ruff format
|
|
50
|
+
|
|
51
|
+
# Run pre-commit hooks manually
|
|
52
|
+
pre-commit run --all-files
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### CLI Usage
|
|
56
|
+
The package provides a `miss-alignment` CLI command:
|
|
57
|
+
```bash
|
|
58
|
+
# Train a model (primary workflow)
|
|
59
|
+
miss-alignment --config-file config.yaml
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Development
|
|
63
|
+
```bash
|
|
64
|
+
# Build the package
|
|
65
|
+
python -m build
|
|
66
|
+
|
|
67
|
+
# Install in editable mode with dependencies
|
|
68
|
+
python -m pip install -e .[dev,test]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Architecture
|
|
72
|
+
|
|
73
|
+
### Core Modules
|
|
74
|
+
|
|
75
|
+
1. **`models/`** - Neural network architectures
|
|
76
|
+
- `MissAlignment`: Main PyTorch Lightning module that wraps the 3D CNN
|
|
77
|
+
- Model variants: `Compact3DConvNet` (default), `Compact3DConvNetGELU`, `Compact3DConvNetWide`, `Compact3DConvNetDeep`, `CompactResNet3D`
|
|
78
|
+
- Uses `TripletMarginRankingLoss` for contrastive learning (comparing aligned vs. misaligned reconstructions)
|
|
79
|
+
|
|
80
|
+
2. **`data/`** - Data loading and synthetic shift generation
|
|
81
|
+
- `MissAlignmentDataModule`: PyTorch Lightning data module managing the reconstruction pool
|
|
82
|
+
- `ReconstructionPoolDataset`: Consumes from a pool of pre-computed 3D patches
|
|
83
|
+
- `shift_generation.py`: Creates synthetic alignment errors (trajectories, jitter, outliers, fractures) for training data
|
|
84
|
+
- `_reconstruction_worker.py`: Multiprocessing workers that generate 3D reconstruction patches in parallel
|
|
85
|
+
- **Architecture note**: Uses a producer-consumer pattern where reconstruction workers populate a temporary pool directory that the dataloader consumes from
|
|
86
|
+
|
|
87
|
+
3. **`alignment/`** - Tilt-series alignment optimization
|
|
88
|
+
- `tilt_series.py`: Core optimization logic using gradient descent on shift parameters
|
|
89
|
+
- `parallel.py`: Distributes alignment across multiple GPU devices
|
|
90
|
+
- `correlation.py`: Traditional correlation-based alignment methods
|
|
91
|
+
- **Key functions**: `optimize_shifts()` supports three modes:
|
|
92
|
+
- `"global"`: Single shift per image
|
|
93
|
+
- `(3, 3, 41)`: 2D warping field per image
|
|
94
|
+
- `(3, 3, 2, 10)`: 3D volume warp grid
|
|
95
|
+
|
|
96
|
+
4. **`train.py`** - Iterative training loop
|
|
97
|
+
- Alternates between model training and tilt-series alignment
|
|
98
|
+
- Each iteration: train model → align tilt-series → use aligned data for next iteration
|
|
99
|
+
- Configured via YAML file (see `config_template.yaml`)
|
|
100
|
+
|
|
101
|
+
### Dependencies on External Libraries
|
|
102
|
+
|
|
103
|
+
- **`warpylib`**: Provides `TiltSeries` and `CubicGrid` for tilt-series geometry and warping
|
|
104
|
+
- **`torch-fourier-*`**: Suite of PyTorch-based Fourier transform utilities (rescale, slice, shift, filter)
|
|
105
|
+
- **`torch-tiltxcorr`**: Cross-correlation utilities for tilt-series
|
|
106
|
+
- **`torch-grid-utils`** and **`torch-cubic-spline-grids`**: Grid manipulation utilities
|
|
107
|
+
|
|
108
|
+
### Configuration System
|
|
109
|
+
|
|
110
|
+
Training is configured via YAML files (template: `src/miss_alignment/config_template.yaml`):
|
|
111
|
+
- **`general`**: Training directory, CTF settings, iteration-specific parameters (downsample, alignment mode)
|
|
112
|
+
- **`model_training`**: Architecture selection, learning rate, loss margin, weight decay, scheduler
|
|
113
|
+
- **`data_loading`**: Batch size, patch size, steps per epoch
|
|
114
|
+
- **`shift_generation`**: Probabilities and magnitudes for synthetic shifts (trajectories, jitter, outliers, fractures)
|
|
115
|
+
- **`tilt_series_alignment`**: Patch size, overlap, batch size for alignment
|
|
116
|
+
|
|
117
|
+
### Data Flow
|
|
118
|
+
|
|
119
|
+
1. **Training**: Tilt-series XML files (`.xml`) → Reconstruction workers → Pool directory (`.pickle` patches triplet) → DataLoader → Model
|
|
120
|
+
2. **Alignment**: Trained model checkpoint → Load tilt-series data → Gradient-based optimization → Output aligned parameters to XML files (`.xml`)
|
|
121
|
+
|
|
122
|
+
## Working with Tilt-Series Data
|
|
123
|
+
|
|
124
|
+
This project uses `warpylib.TiltSeries` as the primary representation of tilt-series metadata. Tilt-series data is stored in `.xml` files that contain:
|
|
125
|
+
- Alignment parameters (tilt angles, tilt axis angles, shifts)
|
|
126
|
+
- Volume dimensions (physical dimensions in Angstroms)
|
|
127
|
+
- Image dimensions (physical dimensions in Angstroms)
|
|
128
|
+
- Path to the image stack (`.st` or `.mrc` files)
|
|
129
|
+
|
|
130
|
+
**Note**: `torch-tomogram` is a dependency only for backward compatibility. Use `warpylib` for all tilt-series operations.
|
|
131
|
+
|
|
132
|
+
### Directory Structure Convention
|
|
133
|
+
|
|
134
|
+
warpylib expects a specific directory structure for tilt-series data. When you have an XML metadata file, the corresponding image stack is located in a subdirectory structure:
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
/path/to/data/
|
|
138
|
+
├── tilt_series_01.xml # XML metadata file
|
|
139
|
+
├── tilt_series_02.xml
|
|
140
|
+
└── tiltstack/ # Stack directory
|
|
141
|
+
├── tilt_series_01/ # Subdirectory per tilt-series
|
|
142
|
+
│ ├── tilt_series_01.st # Image stack
|
|
143
|
+
│ └── tilt_series_01.rawtlt # Optional angle file
|
|
144
|
+
└── tilt_series_02/
|
|
145
|
+
├── tilt_series_02.st
|
|
146
|
+
└── tilt_series_02.rawtlt
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The stack path is automatically derived from the XML path via the `tilt_stack_path` property:
|
|
150
|
+
- XML: `/path/to/data/series.xml`
|
|
151
|
+
- Stack: `/path/to/data/tiltstack/series/series.st`
|
|
152
|
+
|
|
153
|
+
This structure is automatically created when using `convert_pickle_to_xml_helper()` and is expected when loading data with `TiltSeriesData.load_metadata_and_stack()`.
|
|
154
|
+
|
|
155
|
+
### Loading Tilt-Series Data
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from pathlib import Path
|
|
159
|
+
from miss_alignment.data.io import TiltSeriesData
|
|
160
|
+
|
|
161
|
+
# Create TiltSeriesData directly from XML file path
|
|
162
|
+
tilt_series_data = TiltSeriesData(xml_metadata_path=Path("path/to/data.xml"))
|
|
163
|
+
|
|
164
|
+
# Load the TiltSeries object, images, and pixel size
|
|
165
|
+
# The XML file contains volume dimensions, image dimensions, and the path to the stack
|
|
166
|
+
tilt_series, images, pixel_size = tilt_series_data.load_metadata_and_stack(
|
|
167
|
+
downsample=1 # optional downsampling factor
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# Access tilt-series metadata (all torch tensors)
|
|
171
|
+
angles = tilt_series.angles # tilt angles in degrees
|
|
172
|
+
tilt_axis_angles = tilt_series.tilt_axis_angles # tilt axis rotation per image
|
|
173
|
+
tilt_axis_offset_x = tilt_series.tilt_axis_offset_x # X shifts in Angstroms
|
|
174
|
+
tilt_axis_offset_y = tilt_series.tilt_axis_offset_y # Y shifts in Angstroms
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Alternatively, you can load directly with `warpylib`:
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from pathlib import Path
|
|
181
|
+
from warpylib import TiltSeries
|
|
182
|
+
|
|
183
|
+
# Load warpylib TiltSeries directly from XML file
|
|
184
|
+
tilt_series = TiltSeries(Path("path/to/data.xml"))
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### TiltSeries Key Attributes
|
|
188
|
+
|
|
189
|
+
The `warpylib.TiltSeries` object contains:
|
|
190
|
+
- **`angles`**: Tilt angles in degrees (shape: `[n_tilts]`)
|
|
191
|
+
- **`tilt_axis_angles`**: Rotation of tilt axis for each image in degrees (shape: `[n_tilts]`)
|
|
192
|
+
- **`tilt_axis_offset_x`**: X-axis shifts in Angstroms (shape: `[n_tilts]`)
|
|
193
|
+
- **`tilt_axis_offset_y`**: Y-axis shifts in Angstroms (shape: `[n_tilts]`)
|
|
194
|
+
- **`image_dimensions_physical`**: Physical image dimensions in Angstroms (shape: `[2]`)
|
|
195
|
+
- **`volume_dimensions_physical`**: Physical volume dimensions in Angstroms (shape: `[3]`)
|
|
196
|
+
|
|
197
|
+
All attributes are `torch.Tensor` objects.
|
|
198
|
+
|
|
199
|
+
### Performing Reconstructions
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
import torch
|
|
203
|
+
from warpylib.tilt_series.reconstruct_volume import preprocess_tilt_data
|
|
204
|
+
|
|
205
|
+
# Preprocess images (normalize, optionally invert)
|
|
206
|
+
images = preprocess_tilt_data(
|
|
207
|
+
tilt_data=images,
|
|
208
|
+
normalize=True,
|
|
209
|
+
invert=False,
|
|
210
|
+
subvolume_size=64, # patch size for filter calculation
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Define reconstruction position (in Angstroms, in volume coordinate system)
|
|
214
|
+
reconstruction_location = torch.tensor([[x, y, z]], device="cuda")
|
|
215
|
+
|
|
216
|
+
# Perform reconstruction at a specific location
|
|
217
|
+
patch_size = 64 # size of output volume (cubic)
|
|
218
|
+
reconstruction = tilt_series.reconstruct_subvolumes_single(
|
|
219
|
+
tilt_data=images,
|
|
220
|
+
coords=reconstruction_location, # shape: (1, 3) in Angstroms
|
|
221
|
+
pixel_size=pixel_size,
|
|
222
|
+
size=patch_size,
|
|
223
|
+
apply_ctf=True, # apply CTF correction
|
|
224
|
+
angles=torch.tensor([0.0, 0.0, 0.0]), # optional rotation (ZYZ Euler)
|
|
225
|
+
oversampling=2.0, # reconstruction oversampling factor
|
|
226
|
+
)
|
|
227
|
+
# Output shape: (1, patch_size, patch_size, patch_size)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Modifying Alignment Parameters
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
# Modify shifts (all operations in Angstroms)
|
|
234
|
+
tilt_series.tilt_axis_offset_x += shift_x # add X shifts
|
|
235
|
+
tilt_series.tilt_axis_offset_y += shift_y # add Y shifts
|
|
236
|
+
|
|
237
|
+
# Modify angles
|
|
238
|
+
tilt_series.angles = new_angles # set new tilt angles
|
|
239
|
+
tilt_series.tilt_axis_angles = new_tilt_axis_angles # set tilt axis rotation
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Saving Updated Metadata
|
|
243
|
+
|
|
244
|
+
```python
|
|
245
|
+
# Save updated TiltSeries metadata back to the original XML file
|
|
246
|
+
tilt_series_data.save_metadata_to_xml(tilt_series)
|
|
247
|
+
|
|
248
|
+
# Or save to a new XML file
|
|
249
|
+
new_tilt_series_data = tilt_series_data.replace(
|
|
250
|
+
xml_metadata_path=Path("path/to/new_metadata.xml")
|
|
251
|
+
)
|
|
252
|
+
new_tilt_series_data.save_metadata_to_xml(tilt_series)
|
|
253
|
+
|
|
254
|
+
# Alternatively, save directly with warpylib
|
|
255
|
+
tilt_series.save_meta(Path("path/to/metadata.xml"))
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Adding Synthetic Shifts for Testing
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
from miss_alignment.data.shift_generation import (
|
|
262
|
+
JitterGenerator,
|
|
263
|
+
TrajectoryGenerator,
|
|
264
|
+
OutlierGenerator,
|
|
265
|
+
FractureGenerator,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# Create shift generators
|
|
269
|
+
n_tilts = len(tilt_series.angles)
|
|
270
|
+
device = tilt_series.angles.device
|
|
271
|
+
|
|
272
|
+
# Generate shifts (returned in pixels, shape: [n_tilts, 3] for ZYX)
|
|
273
|
+
jitter_shifts = JitterGenerator(jitter_max_std=2.0)(n_tilts, device)
|
|
274
|
+
trajectory_shifts = TrajectoryGenerator(trajectory_max_shift=10.0)(n_tilts, device)
|
|
275
|
+
outlier_shifts = OutlierGenerator(outlier_max_shift=20, max_sequence_length=3)(n_tilts, device)
|
|
276
|
+
fracture_shifts = FractureGenerator(fracture_max_shift=30)(n_tilts, device)
|
|
277
|
+
|
|
278
|
+
# Convert to 2D shifts and apply (need projection matrices)
|
|
279
|
+
from miss_alignment.data.shift_generation import project_shifts_3d_to_2d
|
|
280
|
+
from torch_affine_utils.transforms_3d import Ry, Rz
|
|
281
|
+
|
|
282
|
+
r0 = Ry(-tilt_series.angles, zyx=True)
|
|
283
|
+
r1 = Rz(tilt_series.tilt_axis_angles, zyx=True)
|
|
284
|
+
rotation_matrices = r1 @ r0
|
|
285
|
+
projection_matrices = rotation_matrices[..., 1:3, :3]
|
|
286
|
+
|
|
287
|
+
# Project 3D shifts to 2D (shape: [n_tilts, 2] for YX)
|
|
288
|
+
shifts_2d = project_shifts_3d_to_2d(jitter_shifts, projection_matrices)
|
|
289
|
+
shifts_angstrom = shifts_2d * pixel_size
|
|
290
|
+
|
|
291
|
+
# Apply shifts
|
|
292
|
+
tilt_series.tilt_axis_offset_y += shifts_angstrom[:, 0]
|
|
293
|
+
tilt_series.tilt_axis_offset_x += shifts_angstrom[:, 1]
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Development Notes
|
|
297
|
+
|
|
298
|
+
- **Python version**: Requires Python ≥3.10 (tested primarily on 3.11)
|
|
299
|
+
- **Linting**: Uses `ruff` with line length 88, ignores E712 (comparisons with False for readability)
|
|
300
|
+
- **Pre-commit**: Configured with ruff linter and formatter
|
|
301
|
+
- **Testing**: Uses `pytest` with coverage reporting; warnings treated as errors
|
|
302
|
+
- **Multiprocessing**: Reconstruction workers use multiprocessing with device assignment via `reconstruction_accelerators` parameter
|
|
303
|
+
- **Temporary files**: `MissAlignmentDataModule` creates a temporary pool directory (`RECON_POOL_SIZE` env var controls size, default 1000)
|
|
304
|
+
- **Package manager**: Currently uses conda/pip for environment installation -> would like to move to uv in the future
|
|
305
|
+
|
|
306
|
+
## Bug Reporting and Fixes
|
|
307
|
+
|
|
308
|
+
When working on this codebase, if you encounter potential bugs or implementation issues:
|
|
309
|
+
|
|
310
|
+
1. **Report the issue**: Clearly explain what you found and why it appears to be a bug
|
|
311
|
+
2. **Suggest a fix**: Provide a proposed solution with reasoning
|
|
312
|
+
3. **Implement if appropriate**: For clear bugs (e.g., missing conversions, type inconsistencies, logic errors), implement the fix
|
|
313
|
+
4. **Let the maintainer decide**: The maintainer will evaluate whether it's truly a bug or was intentional design
|
|
314
|
+
|
|
315
|
+
**Examples of bugs to report and fix:**
|
|
316
|
+
- Missing data type conversions (e.g., forgetting to convert a list back to tuple in deserialization)
|
|
317
|
+
- Inconsistent behavior between related functions (e.g., `to_dict()` and `from_dict()` not being symmetric)
|
|
318
|
+
- Logic errors or off-by-one errors
|
|
319
|
+
- Missing error handling
|
|
320
|
+
|
|
321
|
+
**Don't just write tests to conform to buggy behavior** - if the implementation looks wrong, report it and suggest the fix rather than masking it with adjusted test expectations.
|
|
322
|
+
|
|
323
|
+
## File Organization
|
|
324
|
+
|
|
325
|
+
```
|
|
326
|
+
miss-alignment/
|
|
327
|
+
├── src/miss_alignment/
|
|
328
|
+
│ ├── models/ # Neural network architectures
|
|
329
|
+
│ ├── data/ # Data loading, shift generation, reconstruction workers
|
|
330
|
+
│ ├── alignment/ # Alignment optimization algorithms
|
|
331
|
+
│ ├── gradcam/ # Gradient-weighted Class Activation Mapping utilities
|
|
332
|
+
│ ├── train.py # Main training loop
|
|
333
|
+
│ ├── _cli.py # CLI setup with typer
|
|
334
|
+
│ └── config_template.yaml # Configuration template
|
|
335
|
+
├── tests/ # Test suite (mirrors src structure)
|
|
336
|
+
├── examples/ # Example scripts for data processing and visualization
|
|
337
|
+
└── paper/ # Paper-related notebooks and evaluation
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## Important Patterns
|
|
341
|
+
|
|
342
|
+
1. **Configuration-driven**: All training parameters are specified in YAML files
|
|
343
|
+
2. **Iterative refinement**: Training alternates between model training and alignment steps
|
|
344
|
+
3. **Multi-GPU support**: Both training and alignment can use multiple GPUs
|
|
345
|
+
4. **Synthetic data augmentation**: Training uses procedurally generated alignment errors
|
|
346
|
+
5. **Pool-based data loading**: Pre-computed reconstructions in a pool improve training throughput
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Genentech, Inc. and Hubrecht Institute
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|