torch-scattering 0.6.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.
@@ -0,0 +1,115 @@
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
+ *.manifest
32
+ *.spec
33
+
34
+ # Installer logs
35
+ pip-log.txt
36
+ pip-delete-this-directory.txt
37
+
38
+ # Unit test / coverage reports
39
+ htmlcov/
40
+ .tox/
41
+ .coverage
42
+ .coverage.*
43
+ .cache
44
+ nosetests.xml
45
+ coverage.xml
46
+ *.cover
47
+ .hypothesis/
48
+ .pytest_cache/
49
+
50
+ # Files downloaded for unit tests
51
+ **/tests/tmp/
52
+
53
+ # Translations
54
+ *.mo
55
+ *.pot
56
+
57
+ # Django stuff:
58
+ *.log
59
+ local_settings.py
60
+
61
+ # Flask stuff:
62
+ instance/
63
+ .webassets-cache
64
+
65
+ # Scrapy stuff:
66
+ .scrapy
67
+
68
+ # Sphinx documentation
69
+ docs/_build/
70
+
71
+ # PyBuilder
72
+ target/
73
+
74
+ # Jupyter Notebook
75
+ .ipynb_checkpoints
76
+
77
+ # dotenv
78
+ .env
79
+
80
+ # virtualenv
81
+ .venv
82
+ venv/
83
+ ENV/
84
+
85
+ # Spyder project settings
86
+ .spyderproject
87
+ .spyproject
88
+
89
+ # Rope project settings
90
+ .ropeproject
91
+
92
+ # mkdocs documentation
93
+ /site
94
+
95
+ # mypy
96
+ .mypy_cache/
97
+
98
+ # ruff
99
+ .ruff_cache/
100
+
101
+ # IDEs
102
+ .idea/
103
+ .vscode/
104
+
105
+ # Mojo extension compile cache (experimental torch-fourier-slice kernels)
106
+ __mojocache__/
107
+ *.mojopkg
108
+ # experimental demo outputs
109
+ packages/primitives/torch-fourier-slice/examples/*.npz
110
+ packages/primitives/torch-fourier-slice/examples/*.png
111
+ packages/primitives/torch-fourier-slice/examples/*.gif
112
+ # Personal local notes (not for commit)
113
+ notes/*.local.md
114
+
115
+ lightning_logs/
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2020-2026, TeamTomo
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,212 @@
1
+ Metadata-Version: 2.5
2
+ Name: torch-scattering
3
+ Version: 0.6.0
4
+ Summary: Multislice electron scattering simulation in PyTorch
5
+ Project-URL: homepage, https://github.com/teamtomo/teamtomo
6
+ Project-URL: repository, https://github.com/teamtomo/teamtomo
7
+ Author-email: Joel Yeo <joelyeo.is@gmail.com>
8
+ License: BSD-3-Clause
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: License :: OSI Approved :: BSD License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.11
19
+ Requires-Dist: scipy
20
+ Requires-Dist: torch
21
+ Requires-Dist: torch-ctf
22
+ Requires-Dist: torch-grid-utils
23
+ Description-Content-Type: text/markdown
24
+
25
+ # torch-scattering
26
+
27
+ [![License](https://img.shields.io/pypi/l/torch-scattering.svg?color=green)](https://github.com/joelyeois/torch-scattering/raw/main/LICENSE)
28
+ [![PyPI](https://img.shields.io/pypi/v/torch-scattering.svg?color=green)](https://pypi.org/project/torch-scattering)
29
+ [![Python Version](https://img.shields.io/pypi/pyversions/torch-scattering.svg?color=green)](https://python.org)
30
+ [![CI](https://github.com/joelyeois/torch-scattering/actions/workflows/ci.yml/badge.svg)](https://github.com/joelyeois/torch-scattering/actions/workflows/ci.yml)
31
+ [![codecov](https://codecov.io/gh/joelyeois/torch-scattering/branch/main/graph/badge.svg)](https://codecov.io/gh/joelyeois/torch-scattering)
32
+
33
+ Multislice electron scattering simulation in PyTorch, for cryo-EM/cryo-ET forward modelling.
34
+
35
+ ## Overview
36
+
37
+ `torch_scattering` computes the 2D exit wave produced by propagating an electron
38
+ beam through a 3D electrostatic potential in volts. The potential has shape
39
+ `(..., Z, H, W)`, where Z is the beam direction. `pixel_size` is the isotropic
40
+ voxel spacing in Angstroms, so it specifies both the Y/X pixel spacing and the
41
+ Z slice thickness. Every function returns a complex exit wave of shape
42
+ `(..., H, W)`.
43
+
44
+ Real `float32` and `float64` potentials model non-absorbing specimens and can be
45
+ passed directly; callers do not need to cast them to complex. Complex potentials
46
+ remain supported for modelling absorption.
47
+
48
+ Four propagation modes are provided, trading physical accuracy for speed:
49
+
50
+ * `multislice()` - full multislice propagation (Kirkland, *Advanced Computing in
51
+ Electron Microscopy*), alternating transmission through each slice with Fresnel
52
+ propagation to the next. The most accurate mode.
53
+ * `rytov()` - Rytov approximation, accumulating phase in the exponent rather than
54
+ the wave itself.
55
+ * `firstborn()` - first Born approximation, summing single-scattering
56
+ contributions from each slice.
57
+ * `projection()` - projection approximation, treating the specimen as infinitely
58
+ thin and skipping inter-slice propagation entirely. The fastest and least
59
+ accurate mode.
60
+
61
+ All four share the same required inputs and can be swapped in for one another.
62
+ `multislice`, `rytov`, and `firstborn` also accept an `n_slices` argument to
63
+ coarsen the potential into fewer, thicker slabs before propagating.
64
+
65
+ Lower-level, pure-math primitives (`fresnel_propagator`, `transmission_function`,
66
+ `multislice_step`, `chunk_slices`, `interaction_parameter`) are also exposed for
67
+ building custom propagation schemes.
68
+
69
+ ## Installation
70
+
71
+ ```shell
72
+ pip install torch-scattering
73
+ ```
74
+
75
+ ## Usage
76
+
77
+ ```python
78
+ import torch
79
+ from torch_scattering import multislice
80
+
81
+ # A real electrostatic potential in volts, shape (Z, H, W).
82
+ potential = torch.zeros((50, 64, 64), dtype=torch.float32)
83
+
84
+ # propagate a plane wave through it
85
+ exit_wave = multislice(
86
+ potential=potential,
87
+ pixel_size=1.0, # Angstroms
88
+ voltage=300, # kV
89
+ )
90
+ # exit_wave.shape is (64, 64)
91
+ # exit_wave.dtype is torch.complex64
92
+ ```
93
+
94
+ `rytov`, `firstborn`, and `projection` share the same call signature:
95
+
96
+ ```python
97
+ from torch_scattering import firstborn, projection, rytov
98
+
99
+ exit_wave = rytov(potential, pixel_size=1.0, voltage=300)
100
+ exit_wave = firstborn(potential, pixel_size=1.0, voltage=300)
101
+ exit_wave = projection(potential, pixel_size=1.0, voltage=300) # n_slices not applicable
102
+ ```
103
+
104
+ ### Coarsening slices
105
+
106
+ `n_slices` groups the potential into fewer, thicker slabs before propagating.
107
+ By default (`n_slices=None`), every slice of the potential is propagated
108
+ individually - the most accurate but slowest setting.
109
+
110
+ ```python
111
+ # propagate as 10 chunks instead of all 50 slices individually
112
+ exit_wave = multislice(potential, pixel_size=1.0, voltage=300, n_slices=10)
113
+ ```
114
+
115
+ ### Batching
116
+
117
+ All functions accept arbitrary leading batch dimensions on `potential`:
118
+
119
+ ```python
120
+ potential = torch.zeros((8, 50, 64, 64), dtype=torch.complex64) # batch of 8
121
+ exit_wave = multislice(potential, pixel_size=1.0, voltage=300)
122
+ # exit_wave.shape is (8, 64, 64)
123
+ ```
124
+
125
+ ## Structure-to-wave pipeline
126
+
127
+ Structure handling and potential generation are deliberately separate packages.
128
+ They are not runtime dependencies of `torch-scattering`; their real tensor
129
+ output is passed through the public tensor API:
130
+
131
+ ```python
132
+ import pandas as pd
133
+ from torch_calculate_electrostatic_potential import (
134
+ GridConfig,
135
+ potential_from_structure_3d,
136
+ )
137
+ from torch_scattering import multislice
138
+ from torch_structure_manipulation import (
139
+ AtomicStructure,
140
+ annotate_bonding_environments,
141
+ )
142
+
143
+ # mmdf-compatible coordinates are in Angstroms.
144
+ atoms = pd.DataFrame(
145
+ [
146
+ ("A", 1, "ALA", "C", "C", 0.0, 0.0, 0.0),
147
+ ("A", 1, "ALA", "O", "O", 1.2, 0.0, 0.0),
148
+ ("A", 1, "ALA", "CA", "C", -1.2, 0.0, 0.0),
149
+ ("A", 2, "GLY", "N", "N", 2.4, 0.0, 0.0),
150
+ ],
151
+ columns=[
152
+ "chain", "residue_id", "residue", "atom", "element", "x", "y", "z"
153
+ ],
154
+ )
155
+ atoms["b_isotropic"] = 10.0 # Angstrom squared
156
+ atoms["occupancy"] = 1.0
157
+
158
+ # Annotate a complete local residue context, then build the desired structure.
159
+ annotated = annotate_bonding_environments(atoms, include_hydrogens=False)
160
+ structure = AtomicStructure.from_dataframe(annotated.iloc[[0]])
161
+
162
+ grid = GridConfig.from_grid_shape_and_voxel_size(
163
+ grid_shape=(9, 9, 9), # Z, Y, X
164
+ voxel_size=(1.0, 1.0, 1.0), # Angstroms; isotropic for scattering
165
+ center_zyx=(0.0, 0.0, 0.0),
166
+ sublattice_radius=4.0,
167
+ )
168
+ elemental_volts = potential_from_structure_3d(structure, grid)
169
+ bonded_volts = potential_from_structure_3d(
170
+ structure,
171
+ grid,
172
+ scattering_factors="peng_bonded",
173
+ bonded_fallback="error",
174
+ )
175
+
176
+ # Both volumes are real tensors in volts and are accepted directly.
177
+ elemental_wave = multislice(elemental_volts, pixel_size=1.0, voltage=300.0)
178
+ bonded_wave = multislice(bonded_volts, pixel_size=1.0, voltage=300.0)
179
+ # Both waves are complex tensors; voltage is in kV.
180
+ ```
181
+
182
+ `projection()` is a wave-propagation approximation that numerically sums this
183
+ sampled 3D volume along Z. It is distinct from the electrostatic package's
184
+ analytic 2D projected-potential calculation and from projection alignment in
185
+ `torch-fit-in-map`.
186
+
187
+ ## Low-level primitives
188
+
189
+ For building custom propagation schemes directly on top of the multislice
190
+ recurrence:
191
+
192
+ ```python
193
+ import torch
194
+ from torch_grid_utils import fftfreq_grid
195
+ from torch_scattering import (
196
+ fresnel_propagator,
197
+ interaction_parameter,
198
+ multislice_step,
199
+ )
200
+
201
+ frequency_grid = fftfreq_grid(image_shape=(64, 64), rfft=False, spacing=1.0, norm=True)
202
+ propagator = fresnel_propagator(frequency_grid, wavelength=0.01969, dz=1.0)
203
+ sigma = interaction_parameter(voltage=300)
204
+
205
+ wave = torch.ones((64, 64), dtype=torch.complex64)
206
+ potential_slice = torch.zeros((64, 64), dtype=torch.complex64)
207
+ wave = multislice_step(wave, potential_slice, propagator, sigma, dz=1.0)
208
+ ```
209
+
210
+ ## License
211
+
212
+ This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.
@@ -0,0 +1,188 @@
1
+ # torch-scattering
2
+
3
+ [![License](https://img.shields.io/pypi/l/torch-scattering.svg?color=green)](https://github.com/joelyeois/torch-scattering/raw/main/LICENSE)
4
+ [![PyPI](https://img.shields.io/pypi/v/torch-scattering.svg?color=green)](https://pypi.org/project/torch-scattering)
5
+ [![Python Version](https://img.shields.io/pypi/pyversions/torch-scattering.svg?color=green)](https://python.org)
6
+ [![CI](https://github.com/joelyeois/torch-scattering/actions/workflows/ci.yml/badge.svg)](https://github.com/joelyeois/torch-scattering/actions/workflows/ci.yml)
7
+ [![codecov](https://codecov.io/gh/joelyeois/torch-scattering/branch/main/graph/badge.svg)](https://codecov.io/gh/joelyeois/torch-scattering)
8
+
9
+ Multislice electron scattering simulation in PyTorch, for cryo-EM/cryo-ET forward modelling.
10
+
11
+ ## Overview
12
+
13
+ `torch_scattering` computes the 2D exit wave produced by propagating an electron
14
+ beam through a 3D electrostatic potential in volts. The potential has shape
15
+ `(..., Z, H, W)`, where Z is the beam direction. `pixel_size` is the isotropic
16
+ voxel spacing in Angstroms, so it specifies both the Y/X pixel spacing and the
17
+ Z slice thickness. Every function returns a complex exit wave of shape
18
+ `(..., H, W)`.
19
+
20
+ Real `float32` and `float64` potentials model non-absorbing specimens and can be
21
+ passed directly; callers do not need to cast them to complex. Complex potentials
22
+ remain supported for modelling absorption.
23
+
24
+ Four propagation modes are provided, trading physical accuracy for speed:
25
+
26
+ * `multislice()` - full multislice propagation (Kirkland, *Advanced Computing in
27
+ Electron Microscopy*), alternating transmission through each slice with Fresnel
28
+ propagation to the next. The most accurate mode.
29
+ * `rytov()` - Rytov approximation, accumulating phase in the exponent rather than
30
+ the wave itself.
31
+ * `firstborn()` - first Born approximation, summing single-scattering
32
+ contributions from each slice.
33
+ * `projection()` - projection approximation, treating the specimen as infinitely
34
+ thin and skipping inter-slice propagation entirely. The fastest and least
35
+ accurate mode.
36
+
37
+ All four share the same required inputs and can be swapped in for one another.
38
+ `multislice`, `rytov`, and `firstborn` also accept an `n_slices` argument to
39
+ coarsen the potential into fewer, thicker slabs before propagating.
40
+
41
+ Lower-level, pure-math primitives (`fresnel_propagator`, `transmission_function`,
42
+ `multislice_step`, `chunk_slices`, `interaction_parameter`) are also exposed for
43
+ building custom propagation schemes.
44
+
45
+ ## Installation
46
+
47
+ ```shell
48
+ pip install torch-scattering
49
+ ```
50
+
51
+ ## Usage
52
+
53
+ ```python
54
+ import torch
55
+ from torch_scattering import multislice
56
+
57
+ # A real electrostatic potential in volts, shape (Z, H, W).
58
+ potential = torch.zeros((50, 64, 64), dtype=torch.float32)
59
+
60
+ # propagate a plane wave through it
61
+ exit_wave = multislice(
62
+ potential=potential,
63
+ pixel_size=1.0, # Angstroms
64
+ voltage=300, # kV
65
+ )
66
+ # exit_wave.shape is (64, 64)
67
+ # exit_wave.dtype is torch.complex64
68
+ ```
69
+
70
+ `rytov`, `firstborn`, and `projection` share the same call signature:
71
+
72
+ ```python
73
+ from torch_scattering import firstborn, projection, rytov
74
+
75
+ exit_wave = rytov(potential, pixel_size=1.0, voltage=300)
76
+ exit_wave = firstborn(potential, pixel_size=1.0, voltage=300)
77
+ exit_wave = projection(potential, pixel_size=1.0, voltage=300) # n_slices not applicable
78
+ ```
79
+
80
+ ### Coarsening slices
81
+
82
+ `n_slices` groups the potential into fewer, thicker slabs before propagating.
83
+ By default (`n_slices=None`), every slice of the potential is propagated
84
+ individually - the most accurate but slowest setting.
85
+
86
+ ```python
87
+ # propagate as 10 chunks instead of all 50 slices individually
88
+ exit_wave = multislice(potential, pixel_size=1.0, voltage=300, n_slices=10)
89
+ ```
90
+
91
+ ### Batching
92
+
93
+ All functions accept arbitrary leading batch dimensions on `potential`:
94
+
95
+ ```python
96
+ potential = torch.zeros((8, 50, 64, 64), dtype=torch.complex64) # batch of 8
97
+ exit_wave = multislice(potential, pixel_size=1.0, voltage=300)
98
+ # exit_wave.shape is (8, 64, 64)
99
+ ```
100
+
101
+ ## Structure-to-wave pipeline
102
+
103
+ Structure handling and potential generation are deliberately separate packages.
104
+ They are not runtime dependencies of `torch-scattering`; their real tensor
105
+ output is passed through the public tensor API:
106
+
107
+ ```python
108
+ import pandas as pd
109
+ from torch_calculate_electrostatic_potential import (
110
+ GridConfig,
111
+ potential_from_structure_3d,
112
+ )
113
+ from torch_scattering import multislice
114
+ from torch_structure_manipulation import (
115
+ AtomicStructure,
116
+ annotate_bonding_environments,
117
+ )
118
+
119
+ # mmdf-compatible coordinates are in Angstroms.
120
+ atoms = pd.DataFrame(
121
+ [
122
+ ("A", 1, "ALA", "C", "C", 0.0, 0.0, 0.0),
123
+ ("A", 1, "ALA", "O", "O", 1.2, 0.0, 0.0),
124
+ ("A", 1, "ALA", "CA", "C", -1.2, 0.0, 0.0),
125
+ ("A", 2, "GLY", "N", "N", 2.4, 0.0, 0.0),
126
+ ],
127
+ columns=[
128
+ "chain", "residue_id", "residue", "atom", "element", "x", "y", "z"
129
+ ],
130
+ )
131
+ atoms["b_isotropic"] = 10.0 # Angstrom squared
132
+ atoms["occupancy"] = 1.0
133
+
134
+ # Annotate a complete local residue context, then build the desired structure.
135
+ annotated = annotate_bonding_environments(atoms, include_hydrogens=False)
136
+ structure = AtomicStructure.from_dataframe(annotated.iloc[[0]])
137
+
138
+ grid = GridConfig.from_grid_shape_and_voxel_size(
139
+ grid_shape=(9, 9, 9), # Z, Y, X
140
+ voxel_size=(1.0, 1.0, 1.0), # Angstroms; isotropic for scattering
141
+ center_zyx=(0.0, 0.0, 0.0),
142
+ sublattice_radius=4.0,
143
+ )
144
+ elemental_volts = potential_from_structure_3d(structure, grid)
145
+ bonded_volts = potential_from_structure_3d(
146
+ structure,
147
+ grid,
148
+ scattering_factors="peng_bonded",
149
+ bonded_fallback="error",
150
+ )
151
+
152
+ # Both volumes are real tensors in volts and are accepted directly.
153
+ elemental_wave = multislice(elemental_volts, pixel_size=1.0, voltage=300.0)
154
+ bonded_wave = multislice(bonded_volts, pixel_size=1.0, voltage=300.0)
155
+ # Both waves are complex tensors; voltage is in kV.
156
+ ```
157
+
158
+ `projection()` is a wave-propagation approximation that numerically sums this
159
+ sampled 3D volume along Z. It is distinct from the electrostatic package's
160
+ analytic 2D projected-potential calculation and from projection alignment in
161
+ `torch-fit-in-map`.
162
+
163
+ ## Low-level primitives
164
+
165
+ For building custom propagation schemes directly on top of the multislice
166
+ recurrence:
167
+
168
+ ```python
169
+ import torch
170
+ from torch_grid_utils import fftfreq_grid
171
+ from torch_scattering import (
172
+ fresnel_propagator,
173
+ interaction_parameter,
174
+ multislice_step,
175
+ )
176
+
177
+ frequency_grid = fftfreq_grid(image_shape=(64, 64), rfft=False, spacing=1.0, norm=True)
178
+ propagator = fresnel_propagator(frequency_grid, wavelength=0.01969, dz=1.0)
179
+ sigma = interaction_parameter(voltage=300)
180
+
181
+ wave = torch.ones((64, 64), dtype=torch.complex64)
182
+ potential_slice = torch.zeros((64, 64), dtype=torch.complex64)
183
+ wave = multislice_step(wave, potential_slice, propagator, sigma, dz=1.0)
184
+ ```
185
+
186
+ ## License
187
+
188
+ This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.