meteor-maps 0.2.2__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.
- meteor_maps-0.2.2/.github/workflows/deploy.yml +46 -0
- meteor_maps-0.2.2/.github/workflows/lint.yml +39 -0
- meteor_maps-0.2.2/.github/workflows/mypy.yml +35 -0
- meteor_maps-0.2.2/.github/workflows/tests.yml +55 -0
- meteor_maps-0.2.2/.gitignore +171 -0
- meteor_maps-0.2.2/LICENSE +21 -0
- meteor_maps-0.2.2/PKG-INFO +17 -0
- meteor_maps-0.2.2/README.md +58 -0
- meteor_maps-0.2.2/meteor/__init__.py +3 -0
- meteor_maps-0.2.2/meteor/_version.py +16 -0
- meteor_maps-0.2.2/meteor/diffmaps.py +183 -0
- meteor_maps-0.2.2/meteor/io.py +62 -0
- meteor_maps-0.2.2/meteor/iterative.py +259 -0
- meteor_maps-0.2.2/meteor/rsmap.py +430 -0
- meteor_maps-0.2.2/meteor/scale.py +209 -0
- meteor_maps-0.2.2/meteor/scripts/__init__.py +0 -0
- meteor_maps-0.2.2/meteor/scripts/common.py +335 -0
- meteor_maps-0.2.2/meteor/scripts/compute_difference_map.py +168 -0
- meteor_maps-0.2.2/meteor/scripts/compute_iterative_tv_map.py +113 -0
- meteor_maps-0.2.2/meteor/settings.py +49 -0
- meteor_maps-0.2.2/meteor/sfcalc.py +29 -0
- meteor_maps-0.2.2/meteor/testing.py +78 -0
- meteor_maps-0.2.2/meteor/tv.py +213 -0
- meteor_maps-0.2.2/meteor/utils.py +167 -0
- meteor_maps-0.2.2/meteor/validate.py +163 -0
- meteor_maps-0.2.2/meteor_maps.egg-info/PKG-INFO +17 -0
- meteor_maps-0.2.2/meteor_maps.egg-info/SOURCES.txt +59 -0
- meteor_maps-0.2.2/meteor_maps.egg-info/dependency_links.txt +1 -0
- meteor_maps-0.2.2/meteor_maps.egg-info/entry_points.txt +3 -0
- meteor_maps-0.2.2/meteor_maps.egg-info/requires.txt +11 -0
- meteor_maps-0.2.2/meteor_maps.egg-info/top_level.txt +1 -0
- meteor_maps-0.2.2/pyproject.toml +107 -0
- meteor_maps-0.2.2/setup.cfg +4 -0
- meteor_maps-0.2.2/test/__init__.py +0 -0
- meteor_maps-0.2.2/test/conftest.py +27 -0
- meteor_maps-0.2.2/test/data/8a6g-chromophore-removed.cif +2543 -0
- meteor_maps-0.2.2/test/data/8a6g-chromophore-removed.pdb +2439 -0
- meteor_maps-0.2.2/test/data/8a6g.pdb +2712 -0
- meteor_maps-0.2.2/test/data/README.md +47 -0
- meteor_maps-0.2.2/test/data/scaled-test-data.mtz +0 -0
- meteor_maps-0.2.2/test/functional/__init__.py +0 -0
- meteor_maps-0.2.2/test/functional/test_compute_difference_map.py +114 -0
- meteor_maps-0.2.2/test/functional/test_compute_iterative_tv_map.py +68 -0
- meteor_maps-0.2.2/test/functional/test_scale.py +38 -0
- meteor_maps-0.2.2/test/unit/__init__.py +0 -0
- meteor_maps-0.2.2/test/unit/conftest.py +109 -0
- meteor_maps-0.2.2/test/unit/scripts/__init__.py +0 -0
- meteor_maps-0.2.2/test/unit/scripts/conftest.py +42 -0
- meteor_maps-0.2.2/test/unit/scripts/test_common.py +176 -0
- meteor_maps-0.2.2/test/unit/scripts/test_compute_difference_map.py +72 -0
- meteor_maps-0.2.2/test/unit/scripts/test_compute_iterative_tv_map.py +122 -0
- meteor_maps-0.2.2/test/unit/test_diffmaps.py +165 -0
- meteor_maps-0.2.2/test/unit/test_io.py +105 -0
- meteor_maps-0.2.2/test/unit/test_iterative.py +120 -0
- meteor_maps-0.2.2/test/unit/test_rsmap.py +356 -0
- meteor_maps-0.2.2/test/unit/test_scale.py +125 -0
- meteor_maps-0.2.2/test/unit/test_sfcalc.py +70 -0
- meteor_maps-0.2.2/test/unit/test_testing.py +41 -0
- meteor_maps-0.2.2/test/unit/test_tv.py +123 -0
- meteor_maps-0.2.2/test/unit/test_utils.py +129 -0
- meteor_maps-0.2.2/test/unit/test_validate.py +53 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: deploy
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_run:
|
|
5
|
+
branches:
|
|
6
|
+
- master
|
|
7
|
+
workflows:
|
|
8
|
+
- "tests"
|
|
9
|
+
- "mypy"
|
|
10
|
+
- "ruff"
|
|
11
|
+
types:
|
|
12
|
+
- completed
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
deploy:
|
|
16
|
+
name: deploy-to-pypi
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
# only run if previous workflows were a success
|
|
19
|
+
# AND the commit starts with v (meaning it's a tag)
|
|
20
|
+
if: ${{ github.event.workflow_run.conclusion == 'success' && startsWith(github.event.workflow_run.head_commit.message, 'v') }}
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- name: Set up Python
|
|
26
|
+
uses: actions/setup-python@v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.x"
|
|
29
|
+
|
|
30
|
+
- name: install
|
|
31
|
+
run: |
|
|
32
|
+
git tag
|
|
33
|
+
pip install -U pip
|
|
34
|
+
pip install -U build twine
|
|
35
|
+
python -m build
|
|
36
|
+
twine check dist/*
|
|
37
|
+
ls -lh dist
|
|
38
|
+
- name: build and publish
|
|
39
|
+
run: twine upload dist/*
|
|
40
|
+
env:
|
|
41
|
+
TWINE_USERNAME: __token__
|
|
42
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_API_KEY }}
|
|
43
|
+
|
|
44
|
+
- uses: softprops/action-gh-release@v2
|
|
45
|
+
with:
|
|
46
|
+
generate_release_notes: true
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: ruff
|
|
2
|
+
|
|
3
|
+
on: [pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
strategy:
|
|
9
|
+
matrix:
|
|
10
|
+
python-version: ["3.11"]
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- name: Cancel Previous Runs
|
|
14
|
+
uses: styfle/cancel-workflow-action@0.12.1
|
|
15
|
+
with:
|
|
16
|
+
access_token: ${{ github.token }}
|
|
17
|
+
|
|
18
|
+
- name: Checkout
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python-version }}
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install --upgrade pip
|
|
29
|
+
|
|
30
|
+
- name: Lint with Ruff
|
|
31
|
+
run: |
|
|
32
|
+
pip install ruff
|
|
33
|
+
ruff check --output-format=github .
|
|
34
|
+
|
|
35
|
+
- name: Upload coverage to Codecov
|
|
36
|
+
uses: codecov/codecov-action@v3
|
|
37
|
+
with:
|
|
38
|
+
file: ./coverage.xml
|
|
39
|
+
flags: unittests
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: mypy
|
|
2
|
+
|
|
3
|
+
on: [pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
strategy:
|
|
9
|
+
matrix:
|
|
10
|
+
python-version: ["3.11"]
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- name: Cancel Previous Runs
|
|
14
|
+
uses: styfle/cancel-workflow-action@0.12.1
|
|
15
|
+
with:
|
|
16
|
+
access_token: ${{ github.token }}
|
|
17
|
+
|
|
18
|
+
- name: Checkout
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python-version }}
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install --upgrade pip
|
|
29
|
+
|
|
30
|
+
- name: mypy
|
|
31
|
+
run: |
|
|
32
|
+
pip install mypy
|
|
33
|
+
pip install '.[tests]'
|
|
34
|
+
mkdir .mypy_cache
|
|
35
|
+
mypy --install-types --non-interactive meteor/ test/
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
schedule:
|
|
6
|
+
- cron: "0 12 * * 1" # monday at noon GMT
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
name: ${{ matrix.platform }}
|
|
11
|
+
runs-on: ${{ matrix.platform }}
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
python-version:
|
|
16
|
+
- '3.11'
|
|
17
|
+
platform:
|
|
18
|
+
- ubuntu-latest
|
|
19
|
+
- macos-latest
|
|
20
|
+
- windows-latest
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- name: Cancel Previous Runs
|
|
24
|
+
uses: styfle/cancel-workflow-action@0.12.1
|
|
25
|
+
with:
|
|
26
|
+
access_token: ${{ github.token }}
|
|
27
|
+
|
|
28
|
+
- name: Checkout
|
|
29
|
+
uses: actions/checkout@v4
|
|
30
|
+
with:
|
|
31
|
+
lfs: true
|
|
32
|
+
|
|
33
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
34
|
+
uses: actions/setup-python@v5
|
|
35
|
+
with:
|
|
36
|
+
python-version: ${{ matrix.python-version }}
|
|
37
|
+
|
|
38
|
+
- name: Install dependencies
|
|
39
|
+
run: |
|
|
40
|
+
python -m pip install --upgrade pip
|
|
41
|
+
|
|
42
|
+
- name: Test with pytest
|
|
43
|
+
run: |
|
|
44
|
+
pip install '.[tests]'
|
|
45
|
+
pytest test/
|
|
46
|
+
|
|
47
|
+
- name: Upload coverage to Codecov
|
|
48
|
+
uses: codecov/codecov-action@v4
|
|
49
|
+
env:
|
|
50
|
+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
51
|
+
with:
|
|
52
|
+
file: ./coverage.xml
|
|
53
|
+
flags: unittests
|
|
54
|
+
name: codecov-umbrella
|
|
55
|
+
fail_ci_if_error: true
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# large crystallography files -- some of which are used in tests
|
|
7
|
+
# large files are accessed via github LFS
|
|
8
|
+
*.ccp4
|
|
9
|
+
*.map
|
|
10
|
+
*.mtz
|
|
11
|
+
*.pdb
|
|
12
|
+
*.cif
|
|
13
|
+
|
|
14
|
+
# C extensions
|
|
15
|
+
*.so
|
|
16
|
+
|
|
17
|
+
# Distribution / packaging
|
|
18
|
+
_version.py
|
|
19
|
+
.Python
|
|
20
|
+
build/
|
|
21
|
+
develop-eggs/
|
|
22
|
+
dist/
|
|
23
|
+
downloads/
|
|
24
|
+
eggs/
|
|
25
|
+
.eggs/
|
|
26
|
+
lib/
|
|
27
|
+
lib64/
|
|
28
|
+
parts/
|
|
29
|
+
sdist/
|
|
30
|
+
var/
|
|
31
|
+
wheels/
|
|
32
|
+
share/python-wheels/
|
|
33
|
+
*.egg-info/
|
|
34
|
+
.installed.cfg
|
|
35
|
+
*.egg
|
|
36
|
+
MANIFEST
|
|
37
|
+
|
|
38
|
+
# PyInstaller
|
|
39
|
+
# Usually these files are written by a python script from a template
|
|
40
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
41
|
+
*.manifest
|
|
42
|
+
*.spec
|
|
43
|
+
|
|
44
|
+
# Installer logs
|
|
45
|
+
pip-log.txt
|
|
46
|
+
pip-delete-this-directory.txt
|
|
47
|
+
|
|
48
|
+
# Unit test / coverage reports
|
|
49
|
+
htmlcov/
|
|
50
|
+
.tox/
|
|
51
|
+
.nox/
|
|
52
|
+
.coverage
|
|
53
|
+
.coverage.*
|
|
54
|
+
.cache
|
|
55
|
+
nosetests.xml
|
|
56
|
+
coverage.xml
|
|
57
|
+
*.cover
|
|
58
|
+
*.py,cover
|
|
59
|
+
.hypothesis/
|
|
60
|
+
.pytest_cache/
|
|
61
|
+
cover/
|
|
62
|
+
|
|
63
|
+
# Translations
|
|
64
|
+
*.mo
|
|
65
|
+
*.pot
|
|
66
|
+
|
|
67
|
+
# Django stuff:
|
|
68
|
+
*.log
|
|
69
|
+
local_settings.py
|
|
70
|
+
db.sqlite3
|
|
71
|
+
db.sqlite3-journal
|
|
72
|
+
|
|
73
|
+
# Flask stuff:
|
|
74
|
+
instance/
|
|
75
|
+
.webassets-cache
|
|
76
|
+
|
|
77
|
+
# Scrapy stuff:
|
|
78
|
+
.scrapy
|
|
79
|
+
|
|
80
|
+
# Sphinx documentation
|
|
81
|
+
docs/_build/
|
|
82
|
+
|
|
83
|
+
# PyBuilder
|
|
84
|
+
.pybuilder/
|
|
85
|
+
target/
|
|
86
|
+
|
|
87
|
+
# Jupyter Notebook
|
|
88
|
+
.ipynb_checkpoints
|
|
89
|
+
|
|
90
|
+
# IPython
|
|
91
|
+
profile_default/
|
|
92
|
+
ipython_config.py
|
|
93
|
+
|
|
94
|
+
# pyenv
|
|
95
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
96
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
97
|
+
# .python-version
|
|
98
|
+
|
|
99
|
+
# pipenv
|
|
100
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
101
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
102
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
103
|
+
# install all needed dependencies.
|
|
104
|
+
#Pipfile.lock
|
|
105
|
+
|
|
106
|
+
# poetry
|
|
107
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
108
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
109
|
+
# commonly ignored for libraries.
|
|
110
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
111
|
+
#poetry.lock
|
|
112
|
+
|
|
113
|
+
# pdm
|
|
114
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
115
|
+
#pdm.lock
|
|
116
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
117
|
+
# in version control.
|
|
118
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
119
|
+
.pdm.toml
|
|
120
|
+
.pdm-python
|
|
121
|
+
.pdm-build/
|
|
122
|
+
|
|
123
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
124
|
+
__pypackages__/
|
|
125
|
+
|
|
126
|
+
# Celery stuff
|
|
127
|
+
celerybeat-schedule
|
|
128
|
+
celerybeat.pid
|
|
129
|
+
|
|
130
|
+
# SageMath parsed files
|
|
131
|
+
*.sage.py
|
|
132
|
+
|
|
133
|
+
# Environments
|
|
134
|
+
.env
|
|
135
|
+
.venv
|
|
136
|
+
env/
|
|
137
|
+
venv/
|
|
138
|
+
ENV/
|
|
139
|
+
env.bak/
|
|
140
|
+
venv.bak/
|
|
141
|
+
|
|
142
|
+
# Spyder project settings
|
|
143
|
+
.spyderproject
|
|
144
|
+
.spyproject
|
|
145
|
+
|
|
146
|
+
# Rope project settings
|
|
147
|
+
.ropeproject
|
|
148
|
+
|
|
149
|
+
# mkdocs documentation
|
|
150
|
+
/site
|
|
151
|
+
|
|
152
|
+
# mypy
|
|
153
|
+
.mypy_cache/
|
|
154
|
+
.dmypy.json
|
|
155
|
+
dmypy.json
|
|
156
|
+
|
|
157
|
+
# Pyre type checker
|
|
158
|
+
.pyre/
|
|
159
|
+
|
|
160
|
+
# pytype static type analyzer
|
|
161
|
+
.pytype/
|
|
162
|
+
|
|
163
|
+
# Cython debug symbols
|
|
164
|
+
cython_debug/
|
|
165
|
+
|
|
166
|
+
# PyCharm
|
|
167
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
168
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
169
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
170
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
171
|
+
#.idea/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Alisia Fadini and T. J. Lane
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: meteor-maps
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: denoise crystallographic difference maps
|
|
5
|
+
Author-email: Alisia Fadini <af840@cam.ac.uk>, Thomas Lane <thomas.lane@desy.de>
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: numpy>=1.26
|
|
9
|
+
Requires-Dist: scipy>=1.14.0
|
|
10
|
+
Requires-Dist: gemmi>=0.6.6
|
|
11
|
+
Requires-Dist: scikit-image>=0.24.0
|
|
12
|
+
Requires-Dist: reciprocalspaceship>=1.0.2
|
|
13
|
+
Requires-Dist: structlog>=24.4.0
|
|
14
|
+
Provides-Extra: tests
|
|
15
|
+
Requires-Dist: pytest; extra == "tests"
|
|
16
|
+
Requires-Dist: pytest-cov; extra == "tests"
|
|
17
|
+
Requires-Dist: pytest-xdist; extra == "tests"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# METEOR
|
|
2
|
+
Map Enhancement Tools for Ephemeral Occupancy Refinement
|
|
3
|
+
----------
|
|
4
|
+
|
|
5
|
+
[](https://github.com/your_username/your_repo/actions/workflows/tests.yml)
|
|
6
|
+
[](https://github.com/your_username/your_repo/actions/workflows/mypy.yml)
|
|
7
|
+
[](https://github.com/your_username/your_repo/actions/workflows/lint.yml)
|
|
8
|
+
[](https://codecov.io/gh/alisiafadini/meteor)
|
|
9
|
+
|
|
10
|
+
`meteor` is a tool for computing crystallographic difference maps.
|
|
11
|
+
|
|
12
|
+
`meteor` specializes the robust identification of weak signals arising from minor but scientifically interesting populations, such as bound ligands or changes that occur in time-resolved experiments. That said, if you need an difference map, `meteor` can do it!
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## quickstart
|
|
16
|
+
|
|
17
|
+
❗ `meteor` is currently **in beta**. We re-wrote everything recently, moving from a research code to something that can be robustly used as a tool. If you are willing to put up with a few sharp edges, it would be great if you give it a spin and then send us feedback: on how easy/not it was to use and what kinds of scientific results you obtain.
|
|
18
|
+
|
|
19
|
+
Finally: a word of caution. Expect changes in the coming weeks as we stress test the code. You might want to consider this before publishing any results with `meteor` until we exit `beta`.
|
|
20
|
+
|
|
21
|
+
In that vein, for now please install the current master branch as per the following instructions. We'll have a sane
|
|
22
|
+
first stable version soon, which will be deployed straight to `PyPI` and `conda-forge`. Stay posted.
|
|
23
|
+
|
|
24
|
+
First, we recommend you make a new environment. For conda users,
|
|
25
|
+
```
|
|
26
|
+
conda create --name meteor python==3.11 --yes
|
|
27
|
+
conda activate meteor
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then install from github,
|
|
31
|
+
```
|
|
32
|
+
pip install git+https://github.com/alisiafadini/meteor
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Once installed, you will have two command-line scripts. Ask for more info using `-h`:
|
|
36
|
+
```
|
|
37
|
+
meteor.diffmap -h
|
|
38
|
+
meteor.phaseboost -h
|
|
39
|
+
```
|
|
40
|
+
which compute denoised difference maps using the constant-phase approximation _vs._ iterative phase retrieval, respectively.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## philosophy: better science through automation
|
|
44
|
+
|
|
45
|
+
`meteor` aims to:
|
|
46
|
+
|
|
47
|
+
1. maximize signal to noise
|
|
48
|
+
2. be objective and reproducible (minimize user choice & bias)
|
|
49
|
+
3. be easy to use
|
|
50
|
+
|
|
51
|
+
Aim 1 is met using structure factor amplitude weighting (e.g. k-weighting, existing art) and TV denoising (new in the context of crystallography). Aims 2 and 3 are met through automatically setting parameters using negentropy maximization. For all the details, see our paper (coming soon to a preprint server near you).
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
## isomorphous data, please
|
|
55
|
+
|
|
56
|
+
METEOR is only for isomorphous difference maps, meaning the lattices/symmetries of the `native` and `derivative` datasets are comparable. If you need to compare non-isomorphous lattices, check out [matchmaps](https://github.com/rs-station/matchmaps).
|
|
57
|
+
|
|
58
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# file generated by setuptools_scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
TYPE_CHECKING = False
|
|
4
|
+
if TYPE_CHECKING:
|
|
5
|
+
from typing import Tuple, Union
|
|
6
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
|
+
else:
|
|
8
|
+
VERSION_TUPLE = object
|
|
9
|
+
|
|
10
|
+
version: str
|
|
11
|
+
__version__: str
|
|
12
|
+
__version_tuple__: VERSION_TUPLE
|
|
13
|
+
version_tuple: VERSION_TUPLE
|
|
14
|
+
|
|
15
|
+
__version__ = version = '0.2.2'
|
|
16
|
+
__version_tuple__ = version_tuple = (0, 2, 2)
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import reciprocalspaceship as rs
|
|
7
|
+
|
|
8
|
+
from .rsmap import Map, _assert_is_map
|
|
9
|
+
from .settings import DEFAULT_KPARAMS_TO_SCAN, MAP_SAMPLING
|
|
10
|
+
from .utils import filter_common_indices
|
|
11
|
+
from .validate import ScalarMaximizer, negentropy
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def set_common_crystallographic_metadata(map1: Map, map2: Map, *, output: Map) -> None:
|
|
15
|
+
if hasattr(map1, "cell"):
|
|
16
|
+
if hasattr(map2, "cell") and (map1.cell != map2.cell):
|
|
17
|
+
msg = f"`map1.cell` {map1.cell} != `map2.cell` {map2.cell}"
|
|
18
|
+
raise AttributeError(msg)
|
|
19
|
+
output.cell = map1.cell
|
|
20
|
+
|
|
21
|
+
if hasattr(map1, "spacegroup"):
|
|
22
|
+
if hasattr(map2, "spacegroup") and (map1.spacegroup != map2.spacegroup):
|
|
23
|
+
msg = f"`map1.spacegroup` {map1.spacegroup} != "
|
|
24
|
+
msg += f"`map2.spacegroup` {map2.spacegroup}"
|
|
25
|
+
raise AttributeError(msg)
|
|
26
|
+
output.spacegroup = map1.spacegroup
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def compute_difference_map(derivative: Map, native: Map) -> Map:
|
|
30
|
+
"""
|
|
31
|
+
Computes amplitude and phase differences between native and derivative structure factor sets.
|
|
32
|
+
|
|
33
|
+
It converts the amplitude and phase pairs from both the native and derivative structure factor
|
|
34
|
+
sets into complex numbers, computes the difference, and then converts the result back
|
|
35
|
+
into amplitudes and phases.
|
|
36
|
+
|
|
37
|
+
If uncertainty columns are provided for both native and derivative data, it also propagates the
|
|
38
|
+
uncertainty of the difference in amplitudes.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
derivative: Map
|
|
43
|
+
the derivative amplitudes, phases, uncertainties
|
|
44
|
+
native: Map
|
|
45
|
+
the native amplitudes, phases, uncertainties
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
diffmap: Map
|
|
50
|
+
map corresponding to the complex difference (derivative - native)
|
|
51
|
+
"""
|
|
52
|
+
_assert_is_map(derivative, require_uncertainties=False)
|
|
53
|
+
_assert_is_map(native, require_uncertainties=False)
|
|
54
|
+
|
|
55
|
+
derivative, native = filter_common_indices(derivative, native) # type: ignore[assignment]
|
|
56
|
+
|
|
57
|
+
delta_complex = derivative.complex_amplitudes - native.complex_amplitudes
|
|
58
|
+
delta = Map.from_structurefactor(delta_complex, index=native.index)
|
|
59
|
+
|
|
60
|
+
set_common_crystallographic_metadata(derivative, native, output=delta)
|
|
61
|
+
|
|
62
|
+
if derivative.has_uncertainties and native.has_uncertainties:
|
|
63
|
+
prop_uncertainties = np.sqrt(derivative.uncertainties**2 + native.uncertainties**2)
|
|
64
|
+
delta.set_uncertainties(prop_uncertainties)
|
|
65
|
+
|
|
66
|
+
return delta
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def compute_kweights(difference_map: Map, *, k_parameter: float) -> rs.DataSeries:
|
|
70
|
+
"""
|
|
71
|
+
Compute weights for each structure factor based on DeltaF and its uncertainty.
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
difference_map: Map
|
|
76
|
+
A map of structure factor differences (DeltaF).
|
|
77
|
+
k_parameter: float
|
|
78
|
+
A scaling factor applied to the squared `df` values in the weight calculation.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
weights: rs.DataSeries
|
|
83
|
+
A series of computed weights, where higher uncertainties and larger differences lead to
|
|
84
|
+
lower weights.
|
|
85
|
+
"""
|
|
86
|
+
_assert_is_map(difference_map, require_uncertainties=True)
|
|
87
|
+
|
|
88
|
+
inverse_weights = (
|
|
89
|
+
1
|
|
90
|
+
+ (difference_map.uncertainties**2 / (difference_map.uncertainties**2).mean())
|
|
91
|
+
+ k_parameter * (difference_map.amplitudes**2 / (difference_map.amplitudes**2).mean())
|
|
92
|
+
)
|
|
93
|
+
return 1.0 / inverse_weights
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def compute_kweighted_difference_map(derivative: Map, native: Map, *, k_parameter: float) -> Map:
|
|
97
|
+
"""
|
|
98
|
+
Compute k-weighted derivative - native structure factor map.
|
|
99
|
+
|
|
100
|
+
This function first computes the standard difference map using `compute_difference_map`.
|
|
101
|
+
Then, it applies k-weighting to the amplitude differences based on the provided `k_parameter`.
|
|
102
|
+
|
|
103
|
+
Assumes amplitudes have already been scaled prior to invoking this function.
|
|
104
|
+
|
|
105
|
+
Parameters
|
|
106
|
+
----------
|
|
107
|
+
derivative: Map
|
|
108
|
+
the derivative amplitudes, phases, uncertainties
|
|
109
|
+
native: Map
|
|
110
|
+
the native amplitudes, phases, uncertainties
|
|
111
|
+
|
|
112
|
+
Returns
|
|
113
|
+
-------
|
|
114
|
+
diffmap: Map
|
|
115
|
+
the k-weighted difference map
|
|
116
|
+
"""
|
|
117
|
+
# require uncertainties at the beginning
|
|
118
|
+
_assert_is_map(derivative, require_uncertainties=True)
|
|
119
|
+
_assert_is_map(native, require_uncertainties=True)
|
|
120
|
+
|
|
121
|
+
difference_map = compute_difference_map(derivative, native)
|
|
122
|
+
weights = compute_kweights(difference_map, k_parameter=k_parameter)
|
|
123
|
+
|
|
124
|
+
difference_map.amplitudes *= weights
|
|
125
|
+
difference_map.uncertainties *= weights
|
|
126
|
+
|
|
127
|
+
return difference_map
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def max_negentropy_kweighted_difference_map(
|
|
131
|
+
derivative: Map,
|
|
132
|
+
native: Map,
|
|
133
|
+
*,
|
|
134
|
+
k_parameter_values_to_scan: np.ndarray | Sequence[float] = DEFAULT_KPARAMS_TO_SCAN,
|
|
135
|
+
) -> rs.DataSet:
|
|
136
|
+
"""
|
|
137
|
+
Compute k-weighted differences between native and derivative amplitudes and phases.
|
|
138
|
+
|
|
139
|
+
Determines an "optimal" k_parameter, between 0.0 and 1.0, that maximizes the resulting
|
|
140
|
+
difference map negentropy. Assumes that scaling has already been applied to the amplitudes
|
|
141
|
+
before calling this function.
|
|
142
|
+
|
|
143
|
+
Parameters
|
|
144
|
+
----------
|
|
145
|
+
derivative: Map
|
|
146
|
+
the derivative amplitudes, phases, uncertainties
|
|
147
|
+
native: Map
|
|
148
|
+
the native amplitudes, phases, uncertainties
|
|
149
|
+
k_parameter_values_to_scan : np.ndarray | Sequence[float]
|
|
150
|
+
The values to scan to optimize the k-weighting parameter, by default is 0.00, 0.01 ... 1.00
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
kweighted_dataset: rs.DataSet
|
|
155
|
+
dataset with added columns
|
|
156
|
+
|
|
157
|
+
opt_k_parameter: float
|
|
158
|
+
optimized k-weighting parameter
|
|
159
|
+
"""
|
|
160
|
+
_assert_is_map(derivative, require_uncertainties=True)
|
|
161
|
+
_assert_is_map(native, require_uncertainties=True)
|
|
162
|
+
|
|
163
|
+
def negentropy_objective(k_parameter: float) -> float:
|
|
164
|
+
kweighted_dataset = compute_kweighted_difference_map(
|
|
165
|
+
derivative,
|
|
166
|
+
native,
|
|
167
|
+
k_parameter=k_parameter,
|
|
168
|
+
)
|
|
169
|
+
k_weighted_map = kweighted_dataset.to_ccp4_map(map_sampling=MAP_SAMPLING)
|
|
170
|
+
k_weighted_map_array = np.array(k_weighted_map.grid)
|
|
171
|
+
return negentropy(k_weighted_map_array)
|
|
172
|
+
|
|
173
|
+
maximizer = ScalarMaximizer(objective=negentropy_objective)
|
|
174
|
+
maximizer.optimize_over_explicit_values(arguments_to_scan=k_parameter_values_to_scan)
|
|
175
|
+
opt_k_parameter = float(maximizer.argument_optimum)
|
|
176
|
+
|
|
177
|
+
kweighted_dataset = compute_kweighted_difference_map(
|
|
178
|
+
derivative,
|
|
179
|
+
native,
|
|
180
|
+
k_parameter=opt_k_parameter,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
return kweighted_dataset, opt_k_parameter
|