torch-reconstruct-tomogram 0.6.0__py3-none-any.whl

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,26 @@
1
+ """(sub-)tomogram reconstruction and subtilt extraction for cryoET."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ try:
6
+ __version__ = version("torch-reconstruct-tomogram")
7
+ except PackageNotFoundError:
8
+ __version__ = "uninstalled"
9
+ __author__ = "Marten Chaillet, Davide Torre"
10
+ __email__ = "martenchaillet@gmail.com, davidetorre99@gmail.com"
11
+
12
+ from torch_reconstruct_tomogram.projection import (
13
+ extract_particle_tilt_series,
14
+ project_points,
15
+ )
16
+ from torch_reconstruct_tomogram.reconstruct import (
17
+ reconstruct_subvolume,
18
+ reconstruct_tomogram,
19
+ )
20
+
21
+ __all__ = [
22
+ "extract_particle_tilt_series",
23
+ "project_points",
24
+ "reconstruct_subvolume",
25
+ "reconstruct_tomogram",
26
+ ]
@@ -0,0 +1,77 @@
1
+ """Project 3D points into tilt images and crop patches for reconstruction."""
2
+
3
+ from typing import Any
4
+
5
+ import torch
6
+ from torch_grid_utils import dft_center
7
+ from torch_subpixel_crop import subpixel_crop_2d
8
+ from torch_tilt_series import (
9
+ TiltSeries,
10
+ load_tilt_series_images,
11
+ preprocess_tilt_series_images,
12
+ )
13
+
14
+
15
+ def project_points(tilt_series: TiltSeries, points_zyx: torch.Tensor) -> torch.Tensor:
16
+ """Project 3D points to 2D image pixel coordinates.
17
+
18
+ - points are 3D zyx coordinates in Angstroms, relative to the tomogram center
19
+ - tilt_series supplies the projection geometry (`tilt_series.project_points`
20
+ works in Angstroms) and `tilt_series.pixel_spacing` (raises if unset),
21
+ used to convert the projected Angstrom positions to pixels
22
+ - projected 2D points are in pixels, relative to the center of each image
23
+ """
24
+ return tilt_series.project_points(points_zyx) / tilt_series.pixel_spacing
25
+
26
+
27
+ def _extract_particle_tilt_series(
28
+ tilt_series: TiltSeries,
29
+ images: torch.Tensor,
30
+ points_zyx: torch.Tensor,
31
+ sidelength: int,
32
+ return_rfft: bool = True,
33
+ ) -> torch.Tensor:
34
+ """Extract a subtilt-series given already-loaded images."""
35
+ projected_yx = project_points(tilt_series, points_zyx)
36
+ projected_yx = projected_yx + dft_center(
37
+ images.shape[-2:], rfft=False, fftshift=True, device=images.device
38
+ )
39
+ return subpixel_crop_2d(
40
+ image=images,
41
+ positions=projected_yx,
42
+ sidelength=sidelength,
43
+ return_rfft=return_rfft,
44
+ decenter=return_rfft,
45
+ )
46
+
47
+
48
+ def extract_particle_tilt_series(
49
+ tilt_series: TiltSeries,
50
+ points_zyx: torch.Tensor,
51
+ sidelength: int,
52
+ return_rfft: bool = True,
53
+ preprocess: bool = True,
54
+ **preprocessing_kwargs: Any,
55
+ ) -> torch.Tensor:
56
+ """Extract a subtilt-series at 3D location(s) in the sample.
57
+
58
+ Loads (and, by default, preprocesses) the raw tilt images matching
59
+ `tilt_series` via `tilt_series.image_path`/`image_indices`. Preprocessing
60
+ (see `torch_tilt_series.preprocess_tilt_series_images`) by default applies
61
+ plane subtraction, a DC-excluding bandpass with no low-pass (i.e. up to
62
+ Nyquist), and central-crop normalization. `**preprocessing_kwargs` are
63
+ forwarded to `preprocess_tilt_series_images`, overriding any of its
64
+ defaults (`low`, `high`, `falloff`, `bandpass_padding`,
65
+ `subtract_background`, `normalize`) - see that function's docstring for
66
+ details.
67
+ """
68
+ images = load_tilt_series_images(tilt_series)
69
+ if preprocess:
70
+ images = preprocess_tilt_series_images(images, **preprocessing_kwargs)
71
+ return _extract_particle_tilt_series(
72
+ tilt_series,
73
+ images,
74
+ points_zyx,
75
+ sidelength,
76
+ return_rfft=return_rfft,
77
+ )
@@ -0,0 +1,5 @@
1
+ You may remove this file if you don't intend to add types to your package
2
+
3
+ Details at:
4
+
5
+ https://mypy.readthedocs.io/en/stable/installed_packages.html#creating-pep-561-compatible-packages
@@ -0,0 +1,294 @@
1
+ """(sub-)tomogram reconstruction in pytorch."""
2
+
3
+ from typing import Any
4
+
5
+ import einops
6
+ import numpy as np
7
+ import torch
8
+ import torch.nn.functional as F
9
+ from torch_fourier_rescale import fourier_rescale_rfft_2d
10
+ from torch_fourier_slice import insert_central_slices_rfft_3d_multichannel
11
+ from torch_grid_utils import fftfreq_grid
12
+ from torch_tilt_series import (
13
+ TiltSeries,
14
+ load_tilt_series_images,
15
+ preprocess_tilt_series_images,
16
+ )
17
+
18
+ from torch_reconstruct_tomogram.projection import _extract_particle_tilt_series
19
+
20
+ _PAD_FACTOR = 2.0
21
+
22
+
23
+ def _writable(data):
24
+ if isinstance(data, np.ndarray) and not data.flags.writeable:
25
+ data = data.copy()
26
+ return data
27
+
28
+
29
+ def _reconstruct_subvolume(
30
+ tilt_series: TiltSeries,
31
+ images: torch.Tensor,
32
+ points_zyx: torch.Tensor,
33
+ sidelength: int,
34
+ output_pixel_spacing: float | None = None,
35
+ ) -> torch.Tensor:
36
+ """Reconstruct subvolume(s), given already-loaded images."""
37
+ device = images.device
38
+ input_pixel_spacing = tilt_series.pixel_spacing # raises if unset
39
+ if output_pixel_spacing is None:
40
+ output_pixel_spacing = input_pixel_spacing
41
+
42
+ points_zyx = torch.as_tensor(_writable(points_zyx), device=device).float()
43
+ points_zyx, ps = einops.pack([points_zyx], "* zyx")
44
+
45
+ # tomogram -> detector rotation: projection_matrices is sample -> detector
46
+ # only, so compose tomo2sample's rotation in first. Every patch's
47
+ # Fourier-insertion rotation must be expressed relative to the
48
+ # tomogram frame.
49
+ rotation_matrices = (
50
+ tilt_series.projection_matrices[:, :3, :3] @ tilt_series.tomo2sample[:3, :3]
51
+ )
52
+ rotation_matrices = torch.linalg.pinv(rotation_matrices)
53
+
54
+ sidelength_padded_output = int(_PAD_FACTOR * sidelength)
55
+ sidelength_padded_native = max(
56
+ 1,
57
+ round(sidelength_padded_output * output_pixel_spacing / input_pixel_spacing),
58
+ )
59
+
60
+ particle_tilt_series_rfft = _extract_particle_tilt_series(
61
+ tilt_series,
62
+ images,
63
+ points_zyx,
64
+ sidelength=sidelength_padded_native,
65
+ return_rfft=True,
66
+ )
67
+
68
+ particle_tilt_series_rfft = torch.fft.fftshift(particle_tilt_series_rfft, dim=(-2,))
69
+
70
+ particle_tilt_series_rfft = fourier_rescale_rfft_2d(
71
+ dft=particle_tilt_series_rfft,
72
+ image_shape=(sidelength_padded_native, sidelength_padded_native),
73
+ target_shape=(sidelength_padded_output, sidelength_padded_output),
74
+ )
75
+
76
+ particle_tilt_series_rfft = einops.rearrange(
77
+ particle_tilt_series_rfft,
78
+ "n_positions n_tilts h w_rfft -> n_tilts n_positions h w_rfft",
79
+ )
80
+
81
+ patches_rfft, weights = insert_central_slices_rfft_3d_multichannel(
82
+ image_rfft=particle_tilt_series_rfft,
83
+ volume_shape=(sidelength_padded_output,) * 3,
84
+ rotation_matrices=rotation_matrices,
85
+ zyx_matrices=True,
86
+ fftfreq_max=0.5,
87
+ )
88
+
89
+ valid_weights = weights > 1e-3
90
+ patches_rfft[:, valid_weights] /= weights[valid_weights]
91
+
92
+ patches_rfft = torch.fft.ifftshift(patches_rfft, dim=(-3, -2))
93
+
94
+ patches = torch.fft.irfftn(
95
+ patches_rfft,
96
+ s=(sidelength_padded_output,) * 3,
97
+ dim=(-3, -2, -1),
98
+ )
99
+
100
+ patches = torch.fft.ifftshift(patches, dim=(-3, -2, -1))
101
+
102
+ grid = fftfreq_grid(
103
+ image_shape=(sidelength_padded_output,) * 3,
104
+ rfft=False,
105
+ fftshift=True,
106
+ norm=True,
107
+ device=device,
108
+ )
109
+ patches = patches / torch.sinc(grid) ** 2
110
+
111
+ p = (sidelength_padded_output - sidelength) // 2
112
+ patches = F.pad(patches, [-p] * 6)
113
+
114
+ [patches] = einops.unpack(patches, ps, "* d h w")
115
+
116
+ return patches
117
+
118
+
119
+ def reconstruct_subvolume(
120
+ tilt_series: TiltSeries,
121
+ points_zyx: torch.Tensor,
122
+ sidelength: int,
123
+ output_pixel_spacing: float | None = None,
124
+ preprocess: bool = True,
125
+ **preprocessing_kwargs: Any,
126
+ ) -> torch.Tensor:
127
+ """Reconstruct 3D patch(es) at location(s) in the sample.
128
+
129
+ Rank-polymorphic: input (..., 3) -> output (..., d, h, w)
130
+
131
+ - tilt_series supplies the projection geometry,
132
+ - points_zyx are zyx coordinates in Angstroms, relative to the tomogram center
133
+ - sidelength is the output subvolume size in voxels
134
+ - output_pixel_spacing is the voxel size of the output in Angstroms
135
+ (defaults to `tilt_series.pixel_spacing`); the per-tilt 2D crops are
136
+ Fourier-rescaled to this pixel size before 3D reconstruction, so local
137
+ (subvolume) and global (tomogram) reconstructions can each target an
138
+ arbitrary output pixel size independent of the raw data's
139
+ - preprocess, if True (default), applies
140
+ `torch_tilt_series.preprocess_tilt_series_images` to the loaded images
141
+ before reconstruction - by default plane subtraction, a DC-excluding
142
+ bandpass with no low-pass, i.e. up to Nyquist, and central-crop
143
+ normalization
144
+ - `**preprocessing_kwargs` are forwarded to `preprocess_tilt_series_images`,
145
+ overriding any of its defaults (`low`, `high`, `falloff`,
146
+ `bandpass_padding`, `subtract_background`, `normalize`) - see that
147
+ function's docstring for details
148
+ """
149
+ images = load_tilt_series_images(tilt_series)
150
+ if preprocess:
151
+ images = preprocess_tilt_series_images(images, **preprocessing_kwargs)
152
+ return _reconstruct_subvolume(
153
+ tilt_series,
154
+ images,
155
+ points_zyx,
156
+ sidelength,
157
+ output_pixel_spacing=output_pixel_spacing,
158
+ )
159
+
160
+
161
+ def _cosine_taper_window(core_length: int, margin: int, device) -> torch.Tensor:
162
+ """1D cosine-taper window, flat in the middle, tapered at the edges.
163
+
164
+ 1.0 over the central `core_length` samples, cosine-tapered from 0 up to 1
165
+ (and back down to 0) over `margin` samples on each side. Total length is
166
+ core_length + 2 * margin.
167
+ """
168
+ if margin == 0:
169
+ return torch.ones(core_length, device=device)
170
+ ramp = 0.5 * (1 - torch.cos(torch.linspace(0, torch.pi, margin, device=device)))
171
+ core = torch.ones(core_length, device=device)
172
+ return torch.cat([ramp, core, ramp.flip(0)])
173
+
174
+
175
+ def reconstruct_tomogram(
176
+ tilt_series: TiltSeries,
177
+ volume_shape: tuple[int, int, int],
178
+ sidelength: int,
179
+ batch_size: int | None = None,
180
+ output_pixel_spacing: float | None = None,
181
+ preprocess: bool = True,
182
+ blend_margin: int | None = None,
183
+ **preprocessing_kwargs: Any,
184
+ ) -> torch.Tensor:
185
+ """Reconstruct the full tomogram by tiling reconstructed patches in 3D.
186
+
187
+ - tilt_series supplies the projection geometry, plus `image_path`/
188
+ `image_indices` used to load the raw images
189
+ - volume_shape is the (d, h, w) shape of the output tomogram, in voxels
190
+ - sidelength is the spacing between patch centers, in voxels; patches
191
+ are reconstructed on a grid tiling `volume_shape`
192
+ - batch_size, if set, reconstructs at most this many patches per chunk
193
+ (to bound memory usage); defaults to reconstructing all patches at once
194
+ - output_pixel_spacing is the voxel size of the output in Angstroms
195
+ (defaults to `tilt_series.pixel_spacing`)
196
+ - preprocess, if True (default), applies
197
+ `torch_tilt_series.preprocess_tilt_series_images` to the loaded images
198
+ before reconstruction - by default plane subtraction, a DC-excluding
199
+ bandpass with no low-pass, i.e. up to Nyquist, and central-crop
200
+ normalization
201
+ - blend_margin is the extra margin, in voxels, added around each patch
202
+ (total reconstructed patch size is `sidelength + 2 * blend_margin`);
203
+ overlapping patches are cosine-tapered and blended together over this
204
+ margin to avoid seams at patch boundaries. Defaults to
205
+ `sidelength // 4`
206
+ - `**preprocessing_kwargs` are forwarded to `preprocess_tilt_series_images`,
207
+ overriding any of its defaults (`low`, `high`, `falloff`,
208
+ `bandpass_padding`, `subtract_background`, `normalize`) - see that
209
+ function's docstring for details
210
+ """
211
+ images = load_tilt_series_images(tilt_series)
212
+ if preprocess:
213
+ images = preprocess_tilt_series_images(images, **preprocessing_kwargs)
214
+
215
+ pixel_spacing = tilt_series.pixel_spacing # raises if unset
216
+ if output_pixel_spacing is None:
217
+ output_pixel_spacing = pixel_spacing
218
+
219
+ if blend_margin is None:
220
+ blend_margin = sidelength // 4
221
+ patch_sidelength = sidelength + 2 * blend_margin
222
+ half = patch_sidelength // 2
223
+
224
+ d, h, w = volume_shape
225
+ r = sidelength // 2
226
+ device = images.device
227
+
228
+ z_centers = torch.arange(start=r, end=d + r, step=sidelength, device=device)
229
+ y_centers = torch.arange(start=r, end=h + r, step=sidelength, device=device)
230
+ x_centers = torch.arange(start=r, end=w + r, step=sidelength, device=device)
231
+ # absolute 0-indexed voxel coordinates of each patch center
232
+ centers_voxel = torch.stack(
233
+ torch.meshgrid(z_centers, y_centers, x_centers, indexing="ij"), dim=-1
234
+ )
235
+
236
+ volume_center = torch.tensor([d, h, w], device=device) // 2
237
+ centers_zyx_ang = (centers_voxel - volume_center) * output_pixel_spacing
238
+
239
+ window_1d = _cosine_taper_window(sidelength, blend_margin, device="cpu")
240
+ window_3d = (
241
+ window_1d[:, None, None] * window_1d[None, :, None] * window_1d[None, None, :]
242
+ )
243
+
244
+ tomogram_sum = torch.zeros(volume_shape, dtype=torch.float32)
245
+ weight_sum = torch.zeros(volume_shape, dtype=torch.float32)
246
+
247
+ centers_flat, _ = einops.pack([centers_voxel], "* zyx")
248
+ centers_ang_flat, _ = einops.pack([centers_zyx_ang], "* zyx")
249
+ chunk_size = batch_size or len(centers_flat)
250
+
251
+ for start in range(0, len(centers_flat), chunk_size):
252
+ chunk_centers = centers_flat[start : start + chunk_size]
253
+ chunk_centers_ang = centers_ang_flat[start : start + chunk_size]
254
+
255
+ patches_batch = _reconstruct_subvolume(
256
+ tilt_series,
257
+ images,
258
+ chunk_centers_ang,
259
+ patch_sidelength,
260
+ output_pixel_spacing=output_pixel_spacing,
261
+ ).cpu()
262
+
263
+ for j in range(len(patches_batch)):
264
+ cz, cy, cx = chunk_centers[j].tolist()
265
+ z0, y0, x0 = cz - half, cy - half, cx - half
266
+ z1, y1, x1 = (
267
+ z0 + patch_sidelength,
268
+ y0 + patch_sidelength,
269
+ x0 + patch_sidelength,
270
+ )
271
+
272
+ # clip the patch's placement to the volume bounds
273
+ cz0, cy0, cx0 = max(z0, 0), max(y0, 0), max(x0, 0)
274
+ cz1, cy1, cx1 = min(z1, d), min(y1, h), min(x1, w)
275
+ if cz0 >= cz1 or cy0 >= cy1 or cx0 >= cx1:
276
+ continue
277
+
278
+ src = (
279
+ slice(cz0 - z0, cz1 - z0),
280
+ slice(cy0 - y0, cy1 - y0),
281
+ slice(cx0 - x0, cx1 - x0),
282
+ )
283
+ dst = (slice(cz0, cz1), slice(cy0, cy1), slice(cx0, cx1))
284
+ weight_block = window_3d[src]
285
+ tomogram_sum[dst] += patches_batch[j][src] * weight_block
286
+ weight_sum[dst] += weight_block
287
+
288
+ del patches_batch
289
+ if device.type != "cpu":
290
+ torch.cuda.empty_cache()
291
+
292
+ tomogram = tomogram_sum / weight_sum.clamp_min(1e-6)
293
+
294
+ return tomogram.to(device)
@@ -0,0 +1,71 @@
1
+ Metadata-Version: 2.5
2
+ Name: torch-reconstruct-tomogram
3
+ Version: 0.6.0
4
+ Summary: (sub-)tomogram reconstruction and subtilt extraction for cryoET.
5
+ Project-URL: homepage, https://github.com/teamtomo/teamtomo
6
+ Project-URL: repository, https://github.com/teamtomo/teamtomo
7
+ Project-URL: documentation, https://github.com/teamtomo/teamtomo#readme
8
+ Project-URL: changelog, https://github.com/teamtomo/teamtomo#changelog
9
+ Project-URL: Bug Tracker, https://github.com/teamtomo/teamtomo/issues
10
+ Project-URL: Source Code, https://github.com/teamtomo/teamtomo
11
+ Author-email: Marten Chaillet <martenchaillet@gmail.com>, Davide Torre <davidetorre99@gmail.com>
12
+ License: BSD-3-Clause
13
+ License-File: LICENSE
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: License :: OSI Approved :: BSD License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: einops
24
+ Requires-Dist: torch
25
+ Requires-Dist: torch-ctf
26
+ Requires-Dist: torch-fourier-rescale
27
+ Requires-Dist: torch-fourier-slice
28
+ Requires-Dist: torch-grid-utils>=0.0.8
29
+ Requires-Dist: torch-subpixel-crop
30
+ Requires-Dist: torch-tilt-series[io]
31
+ Description-Content-Type: text/markdown
32
+
33
+ # torch-reconstruct-tomogram
34
+
35
+ [![License](https://img.shields.io/pypi/l/torch-reconstruct-tomogram.svg?color=green)](https://github.com/teamtomo/torch-reconstruct-tomogram/raw/main/LICENSE)
36
+ [![PyPI](https://img.shields.io/pypi/v/torch-reconstruct-tomogram.svg?color=green)](https://pypi.org/project/torch-reconstruct-tomogram)
37
+ [![Python Version](https://img.shields.io/pypi/pyversions/torch-reconstruct-tomogram.svg?color=green)](https://python.org)
38
+ [![CI](https://github.com/teamtomo/torch-reconstruct-tomogram/actions/workflows/ci.yml/badge.svg)](https://github.com/teamtomo/torch-reconstruct-tomogram/actions/workflows/ci.yml)
39
+ [![codecov](https://codecov.io/gh/teamtomo/torch-reconstruct-tomogram/branch/main/graph/badge.svg)](https://codecov.io/gh/teamtomo/torch-reconstruct-tomogram)
40
+
41
+ (sub-)Tomogram reconstruction and subtilt extraction for cryo-ET.
42
+
43
+ ## Overview
44
+
45
+ This package provides (sub-)tomogram reconstruction and subtilt extraction driven entirely from a [`torch-tilt-series`](https://github.com/teamtomo/torch-tilt-series) `TiltSeries`. It supports
46
+
47
+ * `extract_particle_tilt_series()`: extract a subtilt-series at 3D location(s) in the sample
48
+ * `reconstruct_subvolume()`: rank-polymorphic reconstruction of 3D patch(es) at location(s) in the sample
49
+ * `reconstruct_tomogram()`: full volume reconstruction by tiling reconstructed patches in 3D
50
+
51
+ `TiltSeries` holds alignment geometry (in Angstroms) plus `image_path`/`image_indices`/`pixel_spacing` metadata. The functions above take a `TiltSeries`, and load and (by default) preprocess the matching raw images internally via `torch_tilt_series.load_tilt_series_images()` / `preprocess_tilt_series_images()` (by default: plane subtraction, a DC-excluding bandpass with no low-pass, i.e. up to Nyquist, and central-crop normalization); pass `**preprocessing_kwargs` to override any of its defaults (`low=`, `high=`, `falloff=`, `bandpass_padding=`, `subtract_background=`, `normalize=`) - see `preprocess_tilt_series_images()`'s docstring for details. `output_pixel_spacing` lets both local (`reconstruct_subvolume`) and global (`reconstruct_tomogram`) reconstruction target an arbitrary output voxel size. Reconstruction happens at the input pixel spacing and is Fourier-rescaled to the requested output size. Reconstruction is performed in Fourier space using central slice insertion. Positions are in `zyx` coordinates, in Angstroms, relative to the tomogram center.
52
+
53
+ ## Installation
54
+
55
+ ```bash
56
+ pip install torch-reconstruct-tomogram
57
+ ```
58
+
59
+ To load a tilt series from AreTomo or ETOMO output, also install the IO dependencies for [`torch-tilt-series`](https://github.com/teamtomo/torch-tilt-series):
60
+
61
+ ```bash
62
+ pip install torch-tilt-series[io]
63
+ ```
64
+
65
+ ## Examples
66
+
67
+ See the [`examples/`](examples/) folder for scripts showing how to load a tilt series, reconstruct subvolumes and tomograms, and save the result.
68
+
69
+ ## License
70
+
71
+ This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.
@@ -0,0 +1,8 @@
1
+ torch_reconstruct_tomogram/__init__.py,sha256=Yfx6btqTSN0UbDn5EZy3BvHNrbq0iSaop5ajsk2pG2Q,712
2
+ torch_reconstruct_tomogram/projection.py,sha256=okn6eJOeYYSHtdbjCz0IBlpuvUuDoIr5Ea_fXMDOQfY,2766
3
+ torch_reconstruct_tomogram/py.typed,sha256=esB4cHc6c07uVkGtqf8at7ttEnprwRxwk8obY8Qumq4,187
4
+ torch_reconstruct_tomogram/reconstruct.py,sha256=urTrH1_9EJjtgFpgDeXKjAIGPSeLO0cPdBgdHIs2EvA,11026
5
+ torch_reconstruct_tomogram-0.6.0.dist-info/METADATA,sha256=RVUq4yqffdZ4F_fk4ZnKwmDBbe04IrNisHRRSeTq_kc,4346
6
+ torch_reconstruct_tomogram-0.6.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
7
+ torch_reconstruct_tomogram-0.6.0.dist-info/licenses/LICENSE,sha256=VGqEjX52frBcv7zRe_8L0JTYMQ2EFvZpH2QNcDgYDZw,1515
8
+ torch_reconstruct_tomogram-0.6.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2020, 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.