mempro 0.2.0__tar.gz → 0.3.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.
- {mempro-0.2.0 → mempro-0.3.0}/PKG-INFO +31 -17
- {mempro-0.2.0 → mempro-0.3.0}/README.md +30 -16
- {mempro-0.2.0 → mempro-0.3.0}/mempro/MemPrO.py +110 -137
- {mempro-0.2.0 → mempro-0.3.0}/mempro.egg-info/PKG-INFO +31 -17
- {mempro-0.2.0 → mempro-0.3.0}/pyproject.toml +1 -1
- {mempro-0.2.0 → mempro-0.3.0}/LICENSE +0 -0
- {mempro-0.2.0 → mempro-0.3.0}/mempro/Insane4MemPrO.py +0 -0
- {mempro-0.2.0 → mempro-0.3.0}/mempro/__init__.py +0 -0
- {mempro-0.2.0 → mempro-0.3.0}/mempro/_cli.py +0 -0
- {mempro-0.2.0 → mempro-0.3.0}/mempro/martini_v3.itp +0 -0
- {mempro-0.2.0 → mempro-0.3.0}/mempro.egg-info/SOURCES.txt +0 -0
- {mempro-0.2.0 → mempro-0.3.0}/mempro.egg-info/dependency_links.txt +0 -0
- {mempro-0.2.0 → mempro-0.3.0}/mempro.egg-info/entry_points.txt +0 -0
- {mempro-0.2.0 → mempro-0.3.0}/mempro.egg-info/requires.txt +0 -0
- {mempro-0.2.0 → mempro-0.3.0}/mempro.egg-info/top_level.txt +0 -0
- {mempro-0.2.0 → mempro-0.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mempro
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Membrane Protein Orientation in Lipid Bilayers
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -14,6 +14,8 @@ Dynamic: license-file
|
|
|
14
14
|
# MemPrO
|
|
15
15
|
Membrane Protein Orientation in Lipid Bilayers. The paper associated with this code can be found [here](https://doi.org/10.1021/acs.jctc.5c01433).
|
|
16
16
|
|
|
17
|
+
[](https://colab.research.google.com/github/pstansfeld/MemPrO/blob/main/MemPrO_Colab.ipynb)
|
|
18
|
+
|
|
17
19
|
Code and parameters from the following were used to help write this code:
|
|
18
20
|
|
|
19
21
|
**Insane:**
|
|
@@ -56,7 +58,9 @@ pip install "matplotlib>=3.8.4"
|
|
|
56
58
|
|
|
57
59
|
The Martini 3 force field file (`martini_v3.itp`) is included in `mempro/`. To use a different one, supply its path with the `-itp` flag; the standard file can be downloaded from [here](https://cgmartini.nl/docs/downloads/force-field-parameters/martini3/particle-definitions.html).
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
### Google Colab
|
|
62
|
+
|
|
63
|
+
MemPrO can also be run without installing anything locally, using the [MemPrO Colab notebook](https://colab.research.google.com/github/pstansfeld/MemPrO/blob/main/MemPrO_Colab.ipynb). It installs MemPrO from PyPI, orients a structure from the PDB, AlphaFold DB or your own upload, shows the results (including a 3D view of the top-ranked orientation), and can optionally predict membrane deformations with MemPrOD. It runs on both CPU and GPU runtimes.
|
|
60
64
|
|
|
61
65
|
## Running MemPrO
|
|
62
66
|
|
|
@@ -72,7 +76,7 @@ python PATH/TO/MemPrO.py -f input_file.pdb
|
|
|
72
76
|
mempro -f input_file.pdb
|
|
73
77
|
```
|
|
74
78
|
|
|
75
|
-
No environment variables are required. By default MemPrO will use
|
|
79
|
+
No environment variables are required. By default MemPrO will use a GPU if JAX can see one, otherwise one CPU device per performance core (see `-nc`), and will look for `Insane4MemPrO.py` and `martini_v3.itp` in the same directory as the script (or the installed package directory). These paths can be overridden with the `-insane` and `-itp` flags if needed.
|
|
76
80
|
|
|
77
81
|
Compiled code is cached in `~/.cache/mempro/jax`, so runs after the first one start about 15 s faster. Set `JAX_COMPILATION_CACHE_DIR` to put the cache somewhere else, or `MEMPRO_NO_JAX_CACHE=1` to turn it off.
|
|
78
82
|
|
|
@@ -82,6 +86,8 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
82
86
|
|
|
83
87
|
* **orientation.txt** — Contains general information about all of the final minima. In general rank 1 is the best orientation, however there are cases where this is not true. `orientation.txt` can then be used to determine the best orientation.
|
|
84
88
|
|
|
89
|
+
* **orientations.pdb** — All final orientations in a single PDB file, one model per rank, ordered by rank.
|
|
90
|
+
|
|
85
91
|
* **local_minima_orientation.png** — A representation of how spread out the local minima are. The more white the image, the more confidence can be placed in rank 1. This is only true in general and there are some cases where this can be safely ignored.
|
|
86
92
|
|
|
87
93
|
* **local_minima_potential.png** — A representation of the potential of the final configuration from a given starting configuration. This complements `local_minima_orientation.png` but in general does not provide much additional information.
|
|
@@ -93,7 +99,7 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
93
99
|
* `PG_potential_curve.png` — The potential curve for the position of the PG cell wall. Only produced with `-pg`.
|
|
94
100
|
* `cross-section_area_curve.png` — The cross-sectional area of the segment of the protein passing through the PG layer. Only produced with `-pg`.
|
|
95
101
|
* `Z_potential_curve.png` — Potential against Z position of the final orientation. Gives an idea of the nature of the minima.
|
|
96
|
-
* `curv_potential_curve.png` — Potential against global membrane curvature for the final orientation. Can indicate whether curvature minimisation should be used.
|
|
102
|
+
* `curv_potential_curve.png` — Potential against global membrane curvature for the final orientation. Can indicate whether curvature minimisation should be used. Not produced with `-dm`.
|
|
97
103
|
|
|
98
104
|
## Flags
|
|
99
105
|
|
|
@@ -107,7 +113,7 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
107
113
|
|
|
108
114
|
**-ng, --grid_size** — Number of initial starting configurations. Defaults to 36. For best efficiency this should be a multiple of the number of CPUs being used. More starting configurations sample the space of minima better, but there are diminishing returns and generally no more than 40 are needed.
|
|
109
115
|
|
|
110
|
-
**-nc, --num_cpus** — Number of CPU cores to use. Defaults to all available cores. For best performance with `-ng`, set `-nc` to a value that divides `-ng` evenly.
|
|
116
|
+
**-nc, --num_cpus** — Number of CPU cores to use. Defaults to the number of performance cores where the system reports them (currently macOS, e.g. 4 on an Apple M4, whose 6 efficiency cores would slow each batch down), otherwise all available cores. For best performance with `-ng`, set `-nc` to a value that divides `-ng` evenly.
|
|
111
117
|
|
|
112
118
|
**-dev, --device** — Device to run on: `auto` (default; GPU if JAX can see one, otherwise CPU), `cpu` or `gpu`. On GPU, all starting configurations are minimised together in a single batch. GPU support needs `pip install "mempro[gpu]"` (Linux, NVIDIA).
|
|
113
119
|
|
|
@@ -115,6 +121,8 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
115
121
|
|
|
116
122
|
**-rank, --rank** — Ranking method for minima: `h` ranks by percentage hits, `p` ranks by potential, `auto` (default) ranks by a value calculated from approximate minima depth and potential.
|
|
117
123
|
|
|
124
|
+
**-seed, --seed** — Seed for the random number generators. Runs with the same seed, input and flags give identical results, provided the number of devices (`-nc`, or the number of GPUs) is also the same. Default is unseeded.
|
|
125
|
+
|
|
118
126
|
**-dm, --dual_membrane** — Toggles dual membrane minimisation. Splits the membrane into an inner and outer membrane and minimises the distance between them. Only use this if your protein spans the periplasm or is a gap junction etc.
|
|
119
127
|
|
|
120
128
|
**-ch, --charge** — Partial charge of the (inner) membrane. The value corresponds to the average charge on a lipid divided by the average area per lipid, representing the average charge across the bilayer sheet. For an E. coli inner membrane this is around -0.008. Default is 0, which gives the best performance in most cases.
|
|
@@ -147,7 +155,7 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
147
155
|
|
|
148
156
|
**-insane, --insane_path** — Path to `Insane4MemPrO.py`. Defaults to the same directory as `MemPrO.py` (or the installed package directory). Only required when using `-bd`.
|
|
149
157
|
|
|
150
|
-
**-bd, --build_system** — Number of final ranked configurations to build as CG MD-ready systems using Insane4MemPrO. Currently only works with coarse grain input files.
|
|
158
|
+
**-bd, --build_system** — Number of final ranked configurations to build as CG MD-ready systems using Insane4MemPrO. Default is 0 (no systems built). Currently only works with coarse grain input files.
|
|
151
159
|
|
|
152
160
|
**-bd_args, --build_arguments** — Arguments to pass to Insane4MemPrO, primarily lipid composition, solvent type etc. Required when using `-bd`.
|
|
153
161
|
|
|
@@ -167,10 +175,16 @@ Orient `input_file.pdb` on a grid of 40 starting configurations with 150 minimis
|
|
|
167
175
|
python PATH/TO/MemPrO.py -f input_file.pdb -o Output_dir/ -ng 40 -ni 150
|
|
168
176
|
```
|
|
169
177
|
|
|
170
|
-
Orient with global curvature minimisation
|
|
178
|
+
Orient with global curvature minimisation:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
python PATH/TO/MemPrO.py -f input_file.pdb -o Output_dir/ -ng 40 -ni 150 -c
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Orient and write per-bead potentials to b-factors (`-wb` is not compatible with `-c`):
|
|
171
185
|
|
|
172
186
|
```
|
|
173
|
-
python PATH/TO/MemPrO.py -f input_file.pdb -o Output_dir/ -ng 40 -ni 150 -
|
|
187
|
+
python PATH/TO/MemPrO.py -f input_file.pdb -o Output_dir/ -ng 40 -ni 150 -wb
|
|
174
188
|
```
|
|
175
189
|
|
|
176
190
|
Orient with a dual membrane system, then build the top 2 ranked configurations as CG systems. The inner membrane contains POPE, POPG and CARD; the outer membrane contains LIPA:
|
|
@@ -255,29 +269,29 @@ MemPrO comes with Insane4MemPrO, a CG system builder based on [Insane](https://g
|
|
|
255
269
|
|
|
256
270
|
#### Peptidoglycan layer options
|
|
257
271
|
|
|
258
|
-
**-pgl** — (
|
|
272
|
+
**-pgl** — (Default: 0) Number of PG layers to place at `-pgl_z`.
|
|
259
273
|
|
|
260
|
-
**-pgl_z** — (
|
|
274
|
+
**-pgl_z** — (Default: 0) Z position of the PG layer relative to the centre of the periplasmic space.
|
|
261
275
|
|
|
262
|
-
**-cper** — (
|
|
276
|
+
**-cper** — (Default: 0.4) Percentage of cross-links.
|
|
263
277
|
|
|
264
|
-
**-lper** — (
|
|
278
|
+
**-lper** — (Default: 0.1) Percentage of cross-links that are between layers.
|
|
265
279
|
|
|
266
|
-
**-per33** — (
|
|
280
|
+
**-per33** — (Default: 0.03) Percentage of 3-3 cross-links; all other cross-links will be 3-4.
|
|
267
281
|
|
|
268
|
-
**-oper** — (
|
|
282
|
+
**-oper** — (Default: 1) Percentage chance of a monomer linking with an oligomer. (Actual chance of link is `cper * oper`.)
|
|
269
283
|
|
|
270
284
|
**-gdist** — (Default: 0.75,4,8.9,0.25,10,45) Distribution of glycan strand lengths. Format as `weight1,stddev1,mean1,weight2,...` where each triple describes a Gaussian. The sum of these Gaussians forms the distribution.
|
|
271
285
|
|
|
272
286
|
#### Protein options
|
|
273
287
|
|
|
274
|
-
**-fudge** — (Default: 0.3) Fudge factor for allowing lipid-protein overlap.
|
|
288
|
+
**-fudge** — (Default: 0.3) Fudge factor for allowing lipid-protein overlap. A value of 0.15 is recommended when using `-def`.
|
|
275
289
|
|
|
276
290
|
#### Solvent options
|
|
277
291
|
|
|
278
292
|
**-sol** — (Required) Solvent type.
|
|
279
293
|
|
|
280
|
-
**-sold** — (Default: 0.5) Solvent
|
|
294
|
+
**-sold** — (Default: 0.5) Solvent diameter.
|
|
281
295
|
|
|
282
296
|
**-solr** — (Default: 0.1) Magnitude of random deviations to solvent positions.
|
|
283
297
|
|
|
@@ -331,7 +345,7 @@ More detailed tutorials are available [here](Insane4MemPrO_tutorials.md).
|
|
|
331
345
|
|
|
332
346
|
If your protein hasn't oriented correctly there are a number of things to try:
|
|
333
347
|
|
|
334
|
-
* Check all orientations by loading `orientations.pdb` and reviewing `
|
|
348
|
+
* Check all orientations by loading `orientations.pdb` and reviewing `orientation.txt`. The correct orientation may not be rank 1.
|
|
335
349
|
* Check `curv_potential_curve.png` to see if your protein prefers a curved membrane. If so, using `-c` will help.
|
|
336
350
|
* Check the PDB file for missing atoms or residues, which can cause the surface to be incorrectly evaluated. Missing atoms should be fixed before orientation.
|
|
337
351
|
* Using `-wb` can be helpful for diagnosing missing atoms — it writes the potential contribution of each residue as a b-factor, viewable in PyMOL.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# MemPrO
|
|
2
2
|
Membrane Protein Orientation in Lipid Bilayers. The paper associated with this code can be found [here](https://doi.org/10.1021/acs.jctc.5c01433).
|
|
3
3
|
|
|
4
|
+
[](https://colab.research.google.com/github/pstansfeld/MemPrO/blob/main/MemPrO_Colab.ipynb)
|
|
5
|
+
|
|
4
6
|
Code and parameters from the following were used to help write this code:
|
|
5
7
|
|
|
6
8
|
**Insane:**
|
|
@@ -43,7 +45,9 @@ pip install "matplotlib>=3.8.4"
|
|
|
43
45
|
|
|
44
46
|
The Martini 3 force field file (`martini_v3.itp`) is included in `mempro/`. To use a different one, supply its path with the `-itp` flag; the standard file can be downloaded from [here](https://cgmartini.nl/docs/downloads/force-field-parameters/martini3/particle-definitions.html).
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
### Google Colab
|
|
49
|
+
|
|
50
|
+
MemPrO can also be run without installing anything locally, using the [MemPrO Colab notebook](https://colab.research.google.com/github/pstansfeld/MemPrO/blob/main/MemPrO_Colab.ipynb). It installs MemPrO from PyPI, orients a structure from the PDB, AlphaFold DB or your own upload, shows the results (including a 3D view of the top-ranked orientation), and can optionally predict membrane deformations with MemPrOD. It runs on both CPU and GPU runtimes.
|
|
47
51
|
|
|
48
52
|
## Running MemPrO
|
|
49
53
|
|
|
@@ -59,7 +63,7 @@ python PATH/TO/MemPrO.py -f input_file.pdb
|
|
|
59
63
|
mempro -f input_file.pdb
|
|
60
64
|
```
|
|
61
65
|
|
|
62
|
-
No environment variables are required. By default MemPrO will use
|
|
66
|
+
No environment variables are required. By default MemPrO will use a GPU if JAX can see one, otherwise one CPU device per performance core (see `-nc`), and will look for `Insane4MemPrO.py` and `martini_v3.itp` in the same directory as the script (or the installed package directory). These paths can be overridden with the `-insane` and `-itp` flags if needed.
|
|
63
67
|
|
|
64
68
|
Compiled code is cached in `~/.cache/mempro/jax`, so runs after the first one start about 15 s faster. Set `JAX_COMPILATION_CACHE_DIR` to put the cache somewhere else, or `MEMPRO_NO_JAX_CACHE=1` to turn it off.
|
|
65
69
|
|
|
@@ -69,6 +73,8 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
69
73
|
|
|
70
74
|
* **orientation.txt** — Contains general information about all of the final minima. In general rank 1 is the best orientation, however there are cases where this is not true. `orientation.txt` can then be used to determine the best orientation.
|
|
71
75
|
|
|
76
|
+
* **orientations.pdb** — All final orientations in a single PDB file, one model per rank, ordered by rank.
|
|
77
|
+
|
|
72
78
|
* **local_minima_orientation.png** — A representation of how spread out the local minima are. The more white the image, the more confidence can be placed in rank 1. This is only true in general and there are some cases where this can be safely ignored.
|
|
73
79
|
|
|
74
80
|
* **local_minima_potential.png** — A representation of the potential of the final configuration from a given starting configuration. This complements `local_minima_orientation.png` but in general does not provide much additional information.
|
|
@@ -80,7 +86,7 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
80
86
|
* `PG_potential_curve.png` — The potential curve for the position of the PG cell wall. Only produced with `-pg`.
|
|
81
87
|
* `cross-section_area_curve.png` — The cross-sectional area of the segment of the protein passing through the PG layer. Only produced with `-pg`.
|
|
82
88
|
* `Z_potential_curve.png` — Potential against Z position of the final orientation. Gives an idea of the nature of the minima.
|
|
83
|
-
* `curv_potential_curve.png` — Potential against global membrane curvature for the final orientation. Can indicate whether curvature minimisation should be used.
|
|
89
|
+
* `curv_potential_curve.png` — Potential against global membrane curvature for the final orientation. Can indicate whether curvature minimisation should be used. Not produced with `-dm`.
|
|
84
90
|
|
|
85
91
|
## Flags
|
|
86
92
|
|
|
@@ -94,7 +100,7 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
94
100
|
|
|
95
101
|
**-ng, --grid_size** — Number of initial starting configurations. Defaults to 36. For best efficiency this should be a multiple of the number of CPUs being used. More starting configurations sample the space of minima better, but there are diminishing returns and generally no more than 40 are needed.
|
|
96
102
|
|
|
97
|
-
**-nc, --num_cpus** — Number of CPU cores to use. Defaults to all available cores. For best performance with `-ng`, set `-nc` to a value that divides `-ng` evenly.
|
|
103
|
+
**-nc, --num_cpus** — Number of CPU cores to use. Defaults to the number of performance cores where the system reports them (currently macOS, e.g. 4 on an Apple M4, whose 6 efficiency cores would slow each batch down), otherwise all available cores. For best performance with `-ng`, set `-nc` to a value that divides `-ng` evenly.
|
|
98
104
|
|
|
99
105
|
**-dev, --device** — Device to run on: `auto` (default; GPU if JAX can see one, otherwise CPU), `cpu` or `gpu`. On GPU, all starting configurations are minimised together in a single batch. GPU support needs `pip install "mempro[gpu]"` (Linux, NVIDIA).
|
|
100
106
|
|
|
@@ -102,6 +108,8 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
102
108
|
|
|
103
109
|
**-rank, --rank** — Ranking method for minima: `h` ranks by percentage hits, `p` ranks by potential, `auto` (default) ranks by a value calculated from approximate minima depth and potential.
|
|
104
110
|
|
|
111
|
+
**-seed, --seed** — Seed for the random number generators. Runs with the same seed, input and flags give identical results, provided the number of devices (`-nc`, or the number of GPUs) is also the same. Default is unseeded.
|
|
112
|
+
|
|
105
113
|
**-dm, --dual_membrane** — Toggles dual membrane minimisation. Splits the membrane into an inner and outer membrane and minimises the distance between them. Only use this if your protein spans the periplasm or is a gap junction etc.
|
|
106
114
|
|
|
107
115
|
**-ch, --charge** — Partial charge of the (inner) membrane. The value corresponds to the average charge on a lipid divided by the average area per lipid, representing the average charge across the bilayer sheet. For an E. coli inner membrane this is around -0.008. Default is 0, which gives the best performance in most cases.
|
|
@@ -134,7 +142,7 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
134
142
|
|
|
135
143
|
**-insane, --insane_path** — Path to `Insane4MemPrO.py`. Defaults to the same directory as `MemPrO.py` (or the installed package directory). Only required when using `-bd`.
|
|
136
144
|
|
|
137
|
-
**-bd, --build_system** — Number of final ranked configurations to build as CG MD-ready systems using Insane4MemPrO. Currently only works with coarse grain input files.
|
|
145
|
+
**-bd, --build_system** — Number of final ranked configurations to build as CG MD-ready systems using Insane4MemPrO. Default is 0 (no systems built). Currently only works with coarse grain input files.
|
|
138
146
|
|
|
139
147
|
**-bd_args, --build_arguments** — Arguments to pass to Insane4MemPrO, primarily lipid composition, solvent type etc. Required when using `-bd`.
|
|
140
148
|
|
|
@@ -154,10 +162,16 @@ Orient `input_file.pdb` on a grid of 40 starting configurations with 150 minimis
|
|
|
154
162
|
python PATH/TO/MemPrO.py -f input_file.pdb -o Output_dir/ -ng 40 -ni 150
|
|
155
163
|
```
|
|
156
164
|
|
|
157
|
-
Orient with global curvature minimisation
|
|
165
|
+
Orient with global curvature minimisation:
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
python PATH/TO/MemPrO.py -f input_file.pdb -o Output_dir/ -ng 40 -ni 150 -c
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Orient and write per-bead potentials to b-factors (`-wb` is not compatible with `-c`):
|
|
158
172
|
|
|
159
173
|
```
|
|
160
|
-
python PATH/TO/MemPrO.py -f input_file.pdb -o Output_dir/ -ng 40 -ni 150 -
|
|
174
|
+
python PATH/TO/MemPrO.py -f input_file.pdb -o Output_dir/ -ng 40 -ni 150 -wb
|
|
161
175
|
```
|
|
162
176
|
|
|
163
177
|
Orient with a dual membrane system, then build the top 2 ranked configurations as CG systems. The inner membrane contains POPE, POPG and CARD; the outer membrane contains LIPA:
|
|
@@ -242,29 +256,29 @@ MemPrO comes with Insane4MemPrO, a CG system builder based on [Insane](https://g
|
|
|
242
256
|
|
|
243
257
|
#### Peptidoglycan layer options
|
|
244
258
|
|
|
245
|
-
**-pgl** — (
|
|
259
|
+
**-pgl** — (Default: 0) Number of PG layers to place at `-pgl_z`.
|
|
246
260
|
|
|
247
|
-
**-pgl_z** — (
|
|
261
|
+
**-pgl_z** — (Default: 0) Z position of the PG layer relative to the centre of the periplasmic space.
|
|
248
262
|
|
|
249
|
-
**-cper** — (
|
|
263
|
+
**-cper** — (Default: 0.4) Percentage of cross-links.
|
|
250
264
|
|
|
251
|
-
**-lper** — (
|
|
265
|
+
**-lper** — (Default: 0.1) Percentage of cross-links that are between layers.
|
|
252
266
|
|
|
253
|
-
**-per33** — (
|
|
267
|
+
**-per33** — (Default: 0.03) Percentage of 3-3 cross-links; all other cross-links will be 3-4.
|
|
254
268
|
|
|
255
|
-
**-oper** — (
|
|
269
|
+
**-oper** — (Default: 1) Percentage chance of a monomer linking with an oligomer. (Actual chance of link is `cper * oper`.)
|
|
256
270
|
|
|
257
271
|
**-gdist** — (Default: 0.75,4,8.9,0.25,10,45) Distribution of glycan strand lengths. Format as `weight1,stddev1,mean1,weight2,...` where each triple describes a Gaussian. The sum of these Gaussians forms the distribution.
|
|
258
272
|
|
|
259
273
|
#### Protein options
|
|
260
274
|
|
|
261
|
-
**-fudge** — (Default: 0.3) Fudge factor for allowing lipid-protein overlap.
|
|
275
|
+
**-fudge** — (Default: 0.3) Fudge factor for allowing lipid-protein overlap. A value of 0.15 is recommended when using `-def`.
|
|
262
276
|
|
|
263
277
|
#### Solvent options
|
|
264
278
|
|
|
265
279
|
**-sol** — (Required) Solvent type.
|
|
266
280
|
|
|
267
|
-
**-sold** — (Default: 0.5) Solvent
|
|
281
|
+
**-sold** — (Default: 0.5) Solvent diameter.
|
|
268
282
|
|
|
269
283
|
**-solr** — (Default: 0.1) Magnitude of random deviations to solvent positions.
|
|
270
284
|
|
|
@@ -318,7 +332,7 @@ More detailed tutorials are available [here](Insane4MemPrO_tutorials.md).
|
|
|
318
332
|
|
|
319
333
|
If your protein hasn't oriented correctly there are a number of things to try:
|
|
320
334
|
|
|
321
|
-
* Check all orientations by loading `orientations.pdb` and reviewing `
|
|
335
|
+
* Check all orientations by loading `orientations.pdb` and reviewing `orientation.txt`. The correct orientation may not be rank 1.
|
|
322
336
|
* Check `curv_potential_curve.png` to see if your protein prefers a curved membrane. If so, using `-c` will help.
|
|
323
337
|
* Check the PDB file for missing atoms or residues, which can cause the surface to be incorrectly evaluated. Missing atoms should be fixed before orientation.
|
|
324
338
|
* Using `-wb` can be helpful for diagnosing missing atoms — it writes the potential contribution of each residue as a b-factor, viewable in PyMOL.
|
|
@@ -13,6 +13,8 @@ from functools import partial, lru_cache
|
|
|
13
13
|
import datetime
|
|
14
14
|
from jax import tree_util
|
|
15
15
|
import shutil
|
|
16
|
+
import shlex
|
|
17
|
+
import sys
|
|
16
18
|
from collections import defaultdict
|
|
17
19
|
|
|
18
20
|
PATH_TO_INSANE = os.environ.get("PATH_TO_INSANE", "")
|
|
@@ -75,11 +77,27 @@ def _pre_parse_device_args():
|
|
|
75
77
|
_pre_parse_device_args()
|
|
76
78
|
|
|
77
79
|
#We need to force JAX to fully utilize a multi-core cpu
|
|
78
|
-
|
|
80
|
+
#By default one device per performance core: each batch of minimisations waits for its slowest device, so on CPUs with
|
|
81
|
+
#efficiency cores (e.g. Apple Silicon, 4P+6E on an M4) using every core is slower (4G1U: 24 s on 10 cores, 16 s on 4)
|
|
82
|
+
def default_device_count():
|
|
83
|
+
try:
|
|
84
|
+
import subprocess
|
|
85
|
+
perf_cores = subprocess.run(["sysctl","-n","hw.perflevel0.physicalcpu"],capture_output=True,text=True,timeout=5)
|
|
86
|
+
if perf_cores.returncode == 0 and perf_cores.stdout.strip().isdigit():
|
|
87
|
+
return int(perf_cores.stdout.strip())
|
|
88
|
+
except (OSError,subprocess.SubprocessError):
|
|
89
|
+
pass
|
|
90
|
+
return os.cpu_count()
|
|
91
|
+
no_cpu = int(os.environ.get("NUM_CPU", default_device_count()))
|
|
79
92
|
os.environ["XLA_FLAGS"] = (os.environ.get("XLA_FLAGS", "")+" --xla_force_host_platform_device_count="+str(no_cpu)).strip()
|
|
93
|
+
jax_version = tuple(int(v) for v in jax.__version__.split(".")[:3] if v.isdigit())
|
|
80
94
|
#The legacy (non-thunk) CPU runtime is faster for MemPrO's scan/cond-heavy loops but only exists up to JAX 0.6.0
|
|
81
|
-
if
|
|
95
|
+
if jax_version <= (0,6,0):
|
|
82
96
|
os.environ["XLA_FLAGS"] += " --xla_cpu_use_thunk_runtime=false"
|
|
97
|
+
#XLA's YNNPACK CPU fusions (JAX >= 0.9) intermittently overflow a worker thread's stack on the large vectorised
|
|
98
|
+
#potentials in MemPrO/MemPrOD (SIGBUS in slinky::eval_non_inlined); turning them off costs no measurable speed
|
|
99
|
+
if jax_version >= (0,9,0) and "xla_cpu_experimental_ynn_fusion_type" not in os.environ["XLA_FLAGS"]:
|
|
100
|
+
os.environ["XLA_FLAGS"] += " --xla_cpu_experimental_ynn_fusion_type="
|
|
83
101
|
|
|
84
102
|
|
|
85
103
|
#This is useful for debugging nans in grad
|
|
@@ -349,17 +367,21 @@ class PDB_helper:
|
|
|
349
367
|
with open(os.path.join(self.fn), "r") as lfile:
|
|
350
368
|
content = lfile.read().split("\n")
|
|
351
369
|
|
|
352
|
-
# Group atom lines
|
|
353
|
-
|
|
370
|
+
# Group consecutive atom lines into residues. A residue ends when the residue name, chain or
|
|
371
|
+
# number changes, so repeated residue numbers in a chain (e.g. martinize2's default
|
|
372
|
+
# renumbering of multi-chain proteins) stay separate residues. write_oriented() writes one
|
|
373
|
+
# line per bead in file order, so there must be exactly one bead per valid ATOM line.
|
|
374
|
+
residues = []
|
|
375
|
+
prev_key = None
|
|
354
376
|
for c in content:
|
|
355
377
|
if len(c) > 54 and "[" not in c and c.startswith("ATOM"):
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
378
|
+
key = (c[17:21].strip(), c[21].strip(), c[22:27])
|
|
379
|
+
if key != prev_key:
|
|
380
|
+
residues.append((key[0], int(c[22:26].strip()), []))
|
|
381
|
+
prev_key = key
|
|
382
|
+
residues[-1][2].append(c)
|
|
360
383
|
|
|
361
|
-
for
|
|
362
|
-
original_resname = resname
|
|
384
|
+
for resname, resid, atoms in residues:
|
|
363
385
|
if resname not in Reses:
|
|
364
386
|
print(f"Unknown residue {resname}, using UNK")
|
|
365
387
|
resname = "UNK"
|
|
@@ -369,7 +391,7 @@ class PDB_helper:
|
|
|
369
391
|
# Collect atom positions
|
|
370
392
|
atom_pos_list = []
|
|
371
393
|
atom_bval_list = []
|
|
372
|
-
|
|
394
|
+
atom_names = []
|
|
373
395
|
|
|
374
396
|
for c in atoms:
|
|
375
397
|
try:
|
|
@@ -377,13 +399,12 @@ class PDB_helper:
|
|
|
377
399
|
y = float(c[38:46].strip())
|
|
378
400
|
z = float(c[46:54].strip())
|
|
379
401
|
b = float(c[60:66].strip())
|
|
380
|
-
atom_num = int(c[22:26].strip())
|
|
381
402
|
pos = np.array([x, y, z])
|
|
382
403
|
|
|
383
404
|
if not np.any(np.isnan(pos)):
|
|
384
405
|
atom_pos_list.append(pos)
|
|
385
406
|
atom_bval_list.append(b)
|
|
386
|
-
|
|
407
|
+
atom_names.append(c[12:16].strip())
|
|
387
408
|
except ValueError:
|
|
388
409
|
continue
|
|
389
410
|
|
|
@@ -391,36 +412,25 @@ class PDB_helper:
|
|
|
391
412
|
print(f"Skipping residue {resname} {resid} due to no valid positions.")
|
|
392
413
|
continue
|
|
393
414
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
if resname == "UNK":
|
|
408
|
-
bead_index == 22
|
|
409
|
-
else:
|
|
410
|
-
bead_index = Beadtype.get(bead_type, -1)
|
|
411
|
-
if bead_index == -1:
|
|
412
|
-
raise ValueError(f"Unknown bead type: {bead_type}")
|
|
413
|
-
self.bead_types.append(bead_index)
|
|
414
|
-
self.reses.append(res_index)
|
|
415
|
-
if resname == "UNK":
|
|
416
|
-
self.poses.append(atom_pos_list[bead_type])
|
|
417
|
-
self.b_vals.append(atom_bval_list[bead_type])
|
|
415
|
+
if resname == "UNK":
|
|
416
|
+
res_bead_types = ["GHOST"]*len(atom_pos_list)
|
|
417
|
+
elif len(bead_list) == len(atom_pos_list):
|
|
418
|
+
res_bead_types = bead_list
|
|
419
|
+
else:
|
|
420
|
+
# Match beads by Martini name (BB, SC1, SC2, ...), falling back to file order
|
|
421
|
+
print(f"Mismatch in bead count vs atom count for {resname} {resid}. Expecting {len(bead_list)}, found {len(atom_pos_list)}. Matching beads by name.")
|
|
422
|
+
res_bead_types = []
|
|
423
|
+
for j, name in enumerate(atom_names):
|
|
424
|
+
if name == "BB":
|
|
425
|
+
k = 0
|
|
426
|
+
elif name.startswith("SC") and name[2:].isdigit():
|
|
427
|
+
k = int(name[2:])
|
|
418
428
|
else:
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
continue
|
|
429
|
+
k = j
|
|
430
|
+
res_bead_types.append(bead_list[min(k, len(bead_list)-1)])
|
|
422
431
|
|
|
423
|
-
|
|
432
|
+
in_range = self.ranges.size != 0 and self.in_ranges(resid)
|
|
433
|
+
for bead_type, pos, b_val in zip(res_bead_types, atom_pos_list, atom_bval_list):
|
|
424
434
|
bead_index = Beadtype.get(bead_type, -1)
|
|
425
435
|
if bead_index == -1:
|
|
426
436
|
raise ValueError(f"Unknown bead type: {bead_type}")
|
|
@@ -429,7 +439,6 @@ class PDB_helper:
|
|
|
429
439
|
self.poses.append(pos)
|
|
430
440
|
|
|
431
441
|
if self.ranges.size != 0:
|
|
432
|
-
in_range = any(self.in_ranges(num) for num in atom_nums)
|
|
433
442
|
self.b_vals.append(1.0 if in_range else 0.0)
|
|
434
443
|
else:
|
|
435
444
|
self.b_vals.append(b_val)
|
|
@@ -558,36 +567,19 @@ class PDB_helper:
|
|
|
558
567
|
total = get_sph_circ(total,jnp.array([0,0]),jnp.pi)
|
|
559
568
|
total_area = jnp.sum(total)
|
|
560
569
|
#jax.debug.print("TA{x}",x=total_area)
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
cen_x = jnp.arctan2(direc[1],direc[0])
|
|
575
|
-
ang_grid = get_sph_circ(ang_grid,jnp.array([cen_x,cen_y]),angle)
|
|
576
|
-
return ang_grid
|
|
577
|
-
ang_grid = jax.lax.cond((dist < srad*3)*(dist>1e-5),nfar,far,ang_grid)
|
|
578
|
-
return ang_grid,ind
|
|
579
|
-
ang_grid,_ = jax.lax.scan(sloopv3_2,ang_grid,jnp.arange(mrad))
|
|
580
|
-
perc = jnp.sum(ang_grid)/total_area
|
|
581
|
-
#jax.debug.print("Perc {x}",x=perc)
|
|
582
|
-
def gthresh(is_surf):
|
|
583
|
-
is_surf = is_surf.at[ind].set(1)
|
|
584
|
-
return is_surf
|
|
585
|
-
def lthresh(is_surf):
|
|
586
|
-
return is_surf
|
|
587
|
-
is_surf = jax.lax.cond(perc<thresh,gthresh,lthresh,is_surf)
|
|
588
|
-
return is_surf,ind
|
|
589
|
-
is_surf,_=jax.lax.scan(sloopv3_1,is_surf,jnp.arange(points.shape[0]))
|
|
590
|
-
return is_surf
|
|
570
|
+
#Each nearby bead (closer than 3*srad) covers a circle of directions; a bead is on the surface if less than
|
|
571
|
+
#thresh of its directions are covered. get_sph_circ sets cells, so overlapping circles combine as a logical OR
|
|
572
|
+
def is_surf_fun(pind):
|
|
573
|
+
direc = points[pind]-points[bpoints[pind]]
|
|
574
|
+
dist = jnp.linalg.norm(direc,axis=1)
|
|
575
|
+
angle = jnp.arccos(jnp.clip(dist/(2*srad),0,1))
|
|
576
|
+
cen_y = jnp.arctan2(direc[:,2],jnp.sqrt(direc[:,0]*direc[:,0]+direc[:,1]*direc[:,1]))
|
|
577
|
+
cen_x = jnp.arctan2(direc[:,1],direc[:,0])
|
|
578
|
+
circles = jax.vmap(get_sph_circ,in_axes=(None,0,0))(jnp.zeros((40,20)),jnp.stack((cen_x,cen_y),axis=1),angle)
|
|
579
|
+
covered = jnp.any((circles > 0)*((dist < srad*3)*(dist>1e-5))[:,None,None],axis=0)
|
|
580
|
+
perc = jnp.sum(jnp.where(covered,total,0.0))/total_area
|
|
581
|
+
return jnp.where(perc<thresh,1.0,0.0)
|
|
582
|
+
return jax.lax.map(is_surf_fun,jnp.arange(points.shape[0]),batch_size=64)
|
|
591
583
|
|
|
592
584
|
#This function gets the surface residues of a given cg protein
|
|
593
585
|
def get_surface(self):
|
|
@@ -602,26 +594,13 @@ class PDB_helper:
|
|
|
602
594
|
|
|
603
595
|
#Calculating normals at each point of the cg protein
|
|
604
596
|
timer = time.time()
|
|
605
|
-
|
|
597
|
+
#The normal at a bead points away from the mean of all beads within 32 A (beads processed in batches to bound memory)
|
|
606
598
|
def normal_fun_2(ind):
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
def in_sphere(normal,posa,posb):
|
|
610
|
-
normal = normal.at[3].set(normal[3]+1)
|
|
611
|
-
normal = normal.at[:3].set(normal[:3]+(-posa+posb))
|
|
612
|
-
return normal
|
|
613
|
-
def not_in_sphere(normal,posa,posb):
|
|
614
|
-
return normal
|
|
615
|
-
normal = jax.lax.cond(jnp.linalg.norm(self.poses[ind]-self.poses[ind_fix])<32,in_sphere,not_in_sphere,normal_count,self.poses[ind],self.poses[ind_fix])#8####################<--------------------------
|
|
616
|
-
return ind_fix,normal
|
|
617
|
-
|
|
618
|
-
_,normals = jax.lax.scan(normal_fun_1,ind,jnp.arange(self.poses.shape[0]))
|
|
619
|
-
normals_sum = jnp.sum(normals,axis=0)
|
|
620
|
-
normal = normals_sum[:3]/normals_sum[3]
|
|
599
|
+
near = jnp.linalg.norm(self.poses-self.poses[ind],axis=1)<32
|
|
600
|
+
normal = jnp.sum(jnp.where(near[:,None],self.poses[ind]-self.poses,0.0),axis=0)/jnp.sum(near)
|
|
621
601
|
normal = normal/jnp.linalg.norm(normal)
|
|
622
602
|
return normal
|
|
623
|
-
|
|
624
|
-
normals = normal_fun_2(shard_nns)
|
|
603
|
+
normals = jax.lax.map(normal_fun_2,jnp.arange(self.poses.shape[0]),batch_size=256)
|
|
625
604
|
|
|
626
605
|
self.normals = jnp.array(jax.device_get(normals))#jax.device_put(normals)#jax.device_put_sharded([normals],[devices[0]])
|
|
627
606
|
|
|
@@ -646,27 +625,13 @@ class PDB_helper:
|
|
|
646
625
|
timer = time.time()
|
|
647
626
|
#Each point on the surface had an asocciated sphere indicating directions which are exposed
|
|
648
627
|
#Here we flag the directions which are free
|
|
649
|
-
|
|
628
|
+
#A direction is free if no bead lies within 4 A of the point 4 A out along the normal plus that direction
|
|
650
629
|
def sphere_fun_3(ind):
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
return 1
|
|
657
|
-
return ind_fix,jax.lax.cond(jnp.linalg.norm(self.poses[ind_fix[0]]+normals[ind_fix[0]]*4-self.poses[ind]+self.ball[ind_fix[1]])<4,in_prot,not_in_prot)
|
|
658
|
-
_,on_surf_arr=jax.lax.scan(sphere_fun_1,jnp.array([ind_fix,ind]),jnp.arange(self.poses.shape[0]))
|
|
659
|
-
on_surf_arr = jnp.array(jax.device_get(on_surf_arr))
|
|
660
|
-
|
|
661
|
-
on_surf = jnp.prod(on_surf_arr)
|
|
662
|
-
return ind_fix,on_surf
|
|
663
|
-
_,on_surf_ball = jax.lax.scan(sphere_fun_2,ind,jnp.arange(self.ball.shape[0]))
|
|
664
|
-
ball_arr = on_surf_ball*self.surface[ind]
|
|
665
|
-
return ball_arr
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
shard_nn = jax.device_put(jnp.arange(self.poses.shape[0]),sharding0)
|
|
669
|
-
spheres = sphere_fun_3(shard_nn)
|
|
630
|
+
test_points = self.poses[ind]+normals[ind]*4+self.ball
|
|
631
|
+
dists = jnp.linalg.norm(test_points[:,None,:]-self.poses[None,:,:],axis=2)
|
|
632
|
+
on_surf_ball = jnp.all(jnp.logical_not(dists<4),axis=1).astype(int)
|
|
633
|
+
return on_surf_ball*self.surface[ind]
|
|
634
|
+
spheres = jax.lax.map(sphere_fun_3,jnp.arange(self.poses.shape[0]),batch_size=32)
|
|
670
635
|
|
|
671
636
|
self.poses = self.poses[:pos_num]
|
|
672
637
|
self.surface = self.surface[:pos_num,0]
|
|
@@ -680,12 +645,8 @@ class PDB_helper:
|
|
|
680
645
|
jax.block_until_ready(self.poses)
|
|
681
646
|
|
|
682
647
|
#Here we set the cartesean directions for each sphere (as before we only had flags)
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
timeser = jnp.transpose(jnp.array([surface_sphere[ind],surface_sphere[ind],surface_sphere[ind]]))
|
|
686
|
-
sphere_poses = sphere_poses.at[ind].set(sphere_poses[ind,:]+timeser*self.ball)
|
|
687
|
-
return sphere_poses,ind
|
|
688
|
-
self.spheres,_ = jax.lax.scan(set_sphere_poses_fun_2,self.spheres,jnp.arange(surface_sphere.shape[0]))
|
|
648
|
+
#surface_number counts the padding rows too (they match surface_poses), and their spheres stay zero
|
|
649
|
+
self.spheres = jnp.zeros((surface_number,self.ball.shape[0],3)).at[:surface_sphere.shape[0]].set(surface_sphere[:,:,None]*self.ball[None,:,:])
|
|
689
650
|
surf_mean = jnp.mean(self.surface_poses,axis=0)
|
|
690
651
|
self.surface_poses = self.surface_poses-surf_mean
|
|
691
652
|
self.poses = self.poses-surf_mean
|
|
@@ -2603,7 +2564,7 @@ class MemBrain:
|
|
|
2603
2564
|
|
|
2604
2565
|
|
|
2605
2566
|
#Builds a CG system using insane
|
|
2606
|
-
def build_oriented(self,orient_dir,build_args):
|
|
2567
|
+
def build_oriented(self,orient_dir,build_args,insane_path):
|
|
2607
2568
|
mins = np.array(self.minima)
|
|
2608
2569
|
no_mins = (mins.shape[0]//5)
|
|
2609
2570
|
min_poses = mins[:no_mins]
|
|
@@ -2626,14 +2587,14 @@ class MemBrain:
|
|
|
2626
2587
|
curv_str = " -curv "+str(10*np.abs(min_curvs[i]))+",0.1,"+str(np.sign(min_curvs[i]-1e-9))
|
|
2627
2588
|
print("Building rank "+str(i+1)+" with Insane4MemPrO:")
|
|
2628
2589
|
cg_sys_dir = rank_dir+"CG_System_rank_"+str(i+1)+"/"
|
|
2629
|
-
run_str = "
|
|
2590
|
+
run_str = shlex.quote(sys.executable)+" "+shlex.quote(insane_path)+" "+build_args.strip()+" -o "+shlex.quote(cg_sys_dir+"CG-system.gro")+" -p "+shlex.quote(cg_sys_dir+"topol.top")+" -f "+shlex.quote(cg_sys_dir+"protein-cg.pdb")+" -x "+str(x_range)+" -y "+str(y_range)+" -z "+str(z_range)+curv_str
|
|
2630
2591
|
if(zdist > 1e-6):
|
|
2631
2592
|
run_str += " -ps "+str(zdist)
|
|
2632
2593
|
if(self.pg_layer_pred):
|
|
2633
2594
|
ps = self.pg_poses[i][0]
|
|
2634
2595
|
xs_pg = self.pg_poses[i][1]
|
|
2635
2596
|
pg_pos = -xs_pg[jnp.argmin(ps)]
|
|
2636
|
-
run_str += " -pgl_z "+str(pg_pos/10.0)+" -o_f "+cg_sys_dir
|
|
2597
|
+
run_str += " -pgl_z "+str(pg_pos/10.0)+" -o_f "+shlex.quote(cg_sys_dir)
|
|
2637
2598
|
#print()
|
|
2638
2599
|
err_val = os.system(run_str)
|
|
2639
2600
|
if(err_val != 0):
|
|
@@ -3154,13 +3115,28 @@ def read_martini_lines(martini_file):
|
|
|
3154
3115
|
with open(martini_file,"r") as mfile:
|
|
3155
3116
|
return tuple(mfile.readlines())
|
|
3156
3117
|
|
|
3157
|
-
#
|
|
3118
|
+
#Index of the first line starting with each 12-character "%6s%6s" bead pair, as in [ nonbond_params ]
|
|
3119
|
+
@lru_cache(maxsize=None)
|
|
3120
|
+
def martini_pair_index(martini_file):
|
|
3121
|
+
index = {}
|
|
3122
|
+
for i,line in enumerate(read_martini_lines(martini_file)):
|
|
3123
|
+
index.setdefault(line[:12],i)
|
|
3124
|
+
return index
|
|
3125
|
+
|
|
3126
|
+
#A fucntion that reads a martini file to get interaction strengths (memoised: each pair is looked up once per run)
|
|
3127
|
+
#Pairs are found through martini_pair_index (one pass over the file); any pair not found at the start of a line
|
|
3128
|
+
#falls back to the original search for the first line containing it
|
|
3129
|
+
@lru_cache(maxsize=None)
|
|
3158
3130
|
def get_int_strength(bead_1,bead_2,martini_file):
|
|
3159
3131
|
if(bead_2 == "GHOST"):
|
|
3160
3132
|
return 0
|
|
3161
3133
|
string = " "*(6-len(bead_1))+bead_1+" "*(6-len(bead_2))+bead_2
|
|
3162
3134
|
string2 = " "*(6-len(bead_2))+bead_2+" "*(6-len(bead_1))+bead_1
|
|
3163
3135
|
content = read_martini_lines(martini_file)
|
|
3136
|
+
index = martini_pair_index(martini_file)
|
|
3137
|
+
found = [index[s] for s in (string,string2) if s in index]
|
|
3138
|
+
if found:
|
|
3139
|
+
return -float(content[min(found)][32:45])
|
|
3164
3140
|
for i,line in enumerate(content):
|
|
3165
3141
|
if(string in line or string2 in line):
|
|
3166
3142
|
return -float(line[32:45])
|
|
@@ -3405,21 +3381,9 @@ def get_sph_circ(grid,cen,angle):
|
|
|
3405
3381
|
dy = jnp.pi/n
|
|
3406
3382
|
xs = jnp.linspace(0,2*jnp.pi-dx,2*n)+dx/2
|
|
3407
3383
|
ys = jnp.linspace(0,jnp.pi-dy,n)+dy/2
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
dist = jnp.arccos(jnp.cos(cen[0])*jnp.cos(xs[ind1])+jnp.sin(cen[0])*jnp.sin(xs[ind1])*jnp.cos(cen[1]-ys[ind]))
|
|
3412
|
-
def langle(grid):
|
|
3413
|
-
grid = grid.at[ind1,ind].set(dx*(jnp.cos(ys[ind]-dy/2)-jnp.cos(ys[ind]+dy/2)))
|
|
3414
|
-
return grid
|
|
3415
|
-
def gangle(grid):
|
|
3416
|
-
return grid
|
|
3417
|
-
grid = jax.lax.cond(dist<angle,langle,gangle,grid)
|
|
3418
|
-
return grid,ind
|
|
3419
|
-
grid,_ = jax.lax.scan(scloop2,grid,jnp.arange(n))
|
|
3420
|
-
return grid,ind
|
|
3421
|
-
grid,_ = jax.lax.scan(scloop1,grid,jnp.arange(2*n))
|
|
3422
|
-
return grid
|
|
3384
|
+
dist = jnp.arccos(jnp.cos(cen[0])*jnp.cos(xs)[:,None]+jnp.sin(cen[0])*jnp.sin(xs)[:,None]*jnp.cos(cen[1]-ys)[None,:])
|
|
3385
|
+
cell_area = dx*(jnp.cos(ys-dy/2)-jnp.cos(ys+dy/2))
|
|
3386
|
+
return jnp.where(dist<angle,jnp.broadcast_to(cell_area[None,:],grid.shape),grid)
|
|
3423
3387
|
|
|
3424
3388
|
def add_Reses(Res, Resitp):
|
|
3425
3389
|
current_res_no = len(Reses)
|
|
@@ -3507,14 +3471,14 @@ def main():
|
|
|
3507
3471
|
os.environ["TF_CPP_MIN_LOG_LEVEL"]="3"
|
|
3508
3472
|
|
|
3509
3473
|
#Reading command line args
|
|
3510
|
-
parser = argparse.ArgumentParser(prog="MemPrO",description="Orients a protein in a membrane. Currently only for E-coli membranes, but this will change in future updates.
|
|
3474
|
+
parser = argparse.ArgumentParser(prog="MemPrO",description="Orients a protein in a membrane. Currently only for E-coli membranes, but this will change in future updates.")
|
|
3511
3475
|
parser.add_argument("-f", "--file_name",help = "Input file name (.pdb)")
|
|
3512
3476
|
parser.add_argument("-o","--output",help="Name of the output directory (Default: Orient)")
|
|
3513
3477
|
parser.add_argument("-ni","--iters",help="Number of minimisation iterations (Default: 150)")
|
|
3514
3478
|
parser.set_defaults(iters=150)
|
|
3515
3479
|
parser.add_argument("-ng","--grid_size",help="Number of starting configurations (Default: 36)")
|
|
3516
3480
|
parser.set_defaults(grid_size=36)
|
|
3517
|
-
parser.add_argument("-nc","--num_cpus",help="Number of CPU cores to use (Default: all available)",type=int)
|
|
3481
|
+
parser.add_argument("-nc","--num_cpus",help="Number of CPU cores to use (Default: performance cores on macOS, otherwise all available)",type=int)
|
|
3518
3482
|
parser.set_defaults(num_cpus=None)
|
|
3519
3483
|
parser.add_argument("-dev","--device",help="Device to run on: auto (GPU if available, otherwise CPU), cpu or gpu (Default: auto)",choices=["auto","cpu","gpu"])
|
|
3520
3484
|
parser.set_defaults(device="auto")
|
|
@@ -3537,7 +3501,7 @@ def main():
|
|
|
3537
3501
|
parser.add_argument("-itp","--itp_file",help="Path to force field (martini_v3.itp)")
|
|
3538
3502
|
parser.set_defaults(itp_file=_default_itp)
|
|
3539
3503
|
parser.add_argument("-insane","--insane_path",help="Path to Insane4MemPrO.py")
|
|
3540
|
-
parser.set_defaults(insane_path=_default_insane)
|
|
3504
|
+
parser.set_defaults(insane_path=PATH_TO_INSANE or _default_insane)
|
|
3541
3505
|
parser.add_argument("-bd","--build_system",help = "Build a MD ready CG-system for ranks < n (Default: n=0)")
|
|
3542
3506
|
parser.set_defaults(build_system=0)
|
|
3543
3507
|
parser.add_argument("-bd_args","--build_arguments",help="Arguments to pass to insane when building system")
|
|
@@ -3564,12 +3528,21 @@ def main():
|
|
|
3564
3528
|
parser.set_defaults(write_bfactors=False)
|
|
3565
3529
|
parser.add_argument("-rank","--rank",help="Ranking method: auto (default), h (hits), p (potential)")
|
|
3566
3530
|
parser.set_defaults(rank="auto")
|
|
3531
|
+
parser.add_argument("-seed","--seed",type=int,help="Seed for the random number generators, for reproducible runs. Results also depend on the number of devices (-nc) (Default: unseeded)")
|
|
3532
|
+
parser.set_defaults(seed=None)
|
|
3567
3533
|
args = parser.parse_args()
|
|
3568
3534
|
|
|
3569
3535
|
if args.file_name is None:
|
|
3570
3536
|
parser.print_help()
|
|
3571
3537
|
sys.exit(0)
|
|
3572
3538
|
|
|
3539
|
+
#All random draws in MemPrO use NumPy's global generator
|
|
3540
|
+
if args.seed is not None:
|
|
3541
|
+
if not 0 <= args.seed < 2**32:
|
|
3542
|
+
print("ERROR: Could not read value of -seed. Must be an integer between 0 and 2^32-1.")
|
|
3543
|
+
exit()
|
|
3544
|
+
np.random.seed(args.seed)
|
|
3545
|
+
|
|
3573
3546
|
fliper = 1
|
|
3574
3547
|
if args.flip:
|
|
3575
3548
|
fliper = -1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mempro
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Membrane Protein Orientation in Lipid Bilayers
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -14,6 +14,8 @@ Dynamic: license-file
|
|
|
14
14
|
# MemPrO
|
|
15
15
|
Membrane Protein Orientation in Lipid Bilayers. The paper associated with this code can be found [here](https://doi.org/10.1021/acs.jctc.5c01433).
|
|
16
16
|
|
|
17
|
+
[](https://colab.research.google.com/github/pstansfeld/MemPrO/blob/main/MemPrO_Colab.ipynb)
|
|
18
|
+
|
|
17
19
|
Code and parameters from the following were used to help write this code:
|
|
18
20
|
|
|
19
21
|
**Insane:**
|
|
@@ -56,7 +58,9 @@ pip install "matplotlib>=3.8.4"
|
|
|
56
58
|
|
|
57
59
|
The Martini 3 force field file (`martini_v3.itp`) is included in `mempro/`. To use a different one, supply its path with the `-itp` flag; the standard file can be downloaded from [here](https://cgmartini.nl/docs/downloads/force-field-parameters/martini3/particle-definitions.html).
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
### Google Colab
|
|
62
|
+
|
|
63
|
+
MemPrO can also be run without installing anything locally, using the [MemPrO Colab notebook](https://colab.research.google.com/github/pstansfeld/MemPrO/blob/main/MemPrO_Colab.ipynb). It installs MemPrO from PyPI, orients a structure from the PDB, AlphaFold DB or your own upload, shows the results (including a 3D view of the top-ranked orientation), and can optionally predict membrane deformations with MemPrOD. It runs on both CPU and GPU runtimes.
|
|
60
64
|
|
|
61
65
|
## Running MemPrO
|
|
62
66
|
|
|
@@ -72,7 +76,7 @@ python PATH/TO/MemPrO.py -f input_file.pdb
|
|
|
72
76
|
mempro -f input_file.pdb
|
|
73
77
|
```
|
|
74
78
|
|
|
75
|
-
No environment variables are required. By default MemPrO will use
|
|
79
|
+
No environment variables are required. By default MemPrO will use a GPU if JAX can see one, otherwise one CPU device per performance core (see `-nc`), and will look for `Insane4MemPrO.py` and `martini_v3.itp` in the same directory as the script (or the installed package directory). These paths can be overridden with the `-insane` and `-itp` flags if needed.
|
|
76
80
|
|
|
77
81
|
Compiled code is cached in `~/.cache/mempro/jax`, so runs after the first one start about 15 s faster. Set `JAX_COMPILATION_CACHE_DIR` to put the cache somewhere else, or `MEMPRO_NO_JAX_CACHE=1` to turn it off.
|
|
78
82
|
|
|
@@ -82,6 +86,8 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
82
86
|
|
|
83
87
|
* **orientation.txt** — Contains general information about all of the final minima. In general rank 1 is the best orientation, however there are cases where this is not true. `orientation.txt` can then be used to determine the best orientation.
|
|
84
88
|
|
|
89
|
+
* **orientations.pdb** — All final orientations in a single PDB file, one model per rank, ordered by rank.
|
|
90
|
+
|
|
85
91
|
* **local_minima_orientation.png** — A representation of how spread out the local minima are. The more white the image, the more confidence can be placed in rank 1. This is only true in general and there are some cases where this can be safely ignored.
|
|
86
92
|
|
|
87
93
|
* **local_minima_potential.png** — A representation of the potential of the final configuration from a given starting configuration. This complements `local_minima_orientation.png` but in general does not provide much additional information.
|
|
@@ -93,7 +99,7 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
93
99
|
* `PG_potential_curve.png` — The potential curve for the position of the PG cell wall. Only produced with `-pg`.
|
|
94
100
|
* `cross-section_area_curve.png` — The cross-sectional area of the segment of the protein passing through the PG layer. Only produced with `-pg`.
|
|
95
101
|
* `Z_potential_curve.png` — Potential against Z position of the final orientation. Gives an idea of the nature of the minima.
|
|
96
|
-
* `curv_potential_curve.png` — Potential against global membrane curvature for the final orientation. Can indicate whether curvature minimisation should be used.
|
|
102
|
+
* `curv_potential_curve.png` — Potential against global membrane curvature for the final orientation. Can indicate whether curvature minimisation should be used. Not produced with `-dm`.
|
|
97
103
|
|
|
98
104
|
## Flags
|
|
99
105
|
|
|
@@ -107,7 +113,7 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
107
113
|
|
|
108
114
|
**-ng, --grid_size** — Number of initial starting configurations. Defaults to 36. For best efficiency this should be a multiple of the number of CPUs being used. More starting configurations sample the space of minima better, but there are diminishing returns and generally no more than 40 are needed.
|
|
109
115
|
|
|
110
|
-
**-nc, --num_cpus** — Number of CPU cores to use. Defaults to all available cores. For best performance with `-ng`, set `-nc` to a value that divides `-ng` evenly.
|
|
116
|
+
**-nc, --num_cpus** — Number of CPU cores to use. Defaults to the number of performance cores where the system reports them (currently macOS, e.g. 4 on an Apple M4, whose 6 efficiency cores would slow each batch down), otherwise all available cores. For best performance with `-ng`, set `-nc` to a value that divides `-ng` evenly.
|
|
111
117
|
|
|
112
118
|
**-dev, --device** — Device to run on: `auto` (default; GPU if JAX can see one, otherwise CPU), `cpu` or `gpu`. On GPU, all starting configurations are minimised together in a single batch. GPU support needs `pip install "mempro[gpu]"` (Linux, NVIDIA).
|
|
113
119
|
|
|
@@ -115,6 +121,8 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
115
121
|
|
|
116
122
|
**-rank, --rank** — Ranking method for minima: `h` ranks by percentage hits, `p` ranks by potential, `auto` (default) ranks by a value calculated from approximate minima depth and potential.
|
|
117
123
|
|
|
124
|
+
**-seed, --seed** — Seed for the random number generators. Runs with the same seed, input and flags give identical results, provided the number of devices (`-nc`, or the number of GPUs) is also the same. Default is unseeded.
|
|
125
|
+
|
|
118
126
|
**-dm, --dual_membrane** — Toggles dual membrane minimisation. Splits the membrane into an inner and outer membrane and minimises the distance between them. Only use this if your protein spans the periplasm or is a gap junction etc.
|
|
119
127
|
|
|
120
128
|
**-ch, --charge** — Partial charge of the (inner) membrane. The value corresponds to the average charge on a lipid divided by the average area per lipid, representing the average charge across the bilayer sheet. For an E. coli inner membrane this is around -0.008. Default is 0, which gives the best performance in most cases.
|
|
@@ -147,7 +155,7 @@ MemPrO is intended to be run on PDB files, and will output the following files:
|
|
|
147
155
|
|
|
148
156
|
**-insane, --insane_path** — Path to `Insane4MemPrO.py`. Defaults to the same directory as `MemPrO.py` (or the installed package directory). Only required when using `-bd`.
|
|
149
157
|
|
|
150
|
-
**-bd, --build_system** — Number of final ranked configurations to build as CG MD-ready systems using Insane4MemPrO. Currently only works with coarse grain input files.
|
|
158
|
+
**-bd, --build_system** — Number of final ranked configurations to build as CG MD-ready systems using Insane4MemPrO. Default is 0 (no systems built). Currently only works with coarse grain input files.
|
|
151
159
|
|
|
152
160
|
**-bd_args, --build_arguments** — Arguments to pass to Insane4MemPrO, primarily lipid composition, solvent type etc. Required when using `-bd`.
|
|
153
161
|
|
|
@@ -167,10 +175,16 @@ Orient `input_file.pdb` on a grid of 40 starting configurations with 150 minimis
|
|
|
167
175
|
python PATH/TO/MemPrO.py -f input_file.pdb -o Output_dir/ -ng 40 -ni 150
|
|
168
176
|
```
|
|
169
177
|
|
|
170
|
-
Orient with global curvature minimisation
|
|
178
|
+
Orient with global curvature minimisation:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
python PATH/TO/MemPrO.py -f input_file.pdb -o Output_dir/ -ng 40 -ni 150 -c
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Orient and write per-bead potentials to b-factors (`-wb` is not compatible with `-c`):
|
|
171
185
|
|
|
172
186
|
```
|
|
173
|
-
python PATH/TO/MemPrO.py -f input_file.pdb -o Output_dir/ -ng 40 -ni 150 -
|
|
187
|
+
python PATH/TO/MemPrO.py -f input_file.pdb -o Output_dir/ -ng 40 -ni 150 -wb
|
|
174
188
|
```
|
|
175
189
|
|
|
176
190
|
Orient with a dual membrane system, then build the top 2 ranked configurations as CG systems. The inner membrane contains POPE, POPG and CARD; the outer membrane contains LIPA:
|
|
@@ -255,29 +269,29 @@ MemPrO comes with Insane4MemPrO, a CG system builder based on [Insane](https://g
|
|
|
255
269
|
|
|
256
270
|
#### Peptidoglycan layer options
|
|
257
271
|
|
|
258
|
-
**-pgl** — (
|
|
272
|
+
**-pgl** — (Default: 0) Number of PG layers to place at `-pgl_z`.
|
|
259
273
|
|
|
260
|
-
**-pgl_z** — (
|
|
274
|
+
**-pgl_z** — (Default: 0) Z position of the PG layer relative to the centre of the periplasmic space.
|
|
261
275
|
|
|
262
|
-
**-cper** — (
|
|
276
|
+
**-cper** — (Default: 0.4) Percentage of cross-links.
|
|
263
277
|
|
|
264
|
-
**-lper** — (
|
|
278
|
+
**-lper** — (Default: 0.1) Percentage of cross-links that are between layers.
|
|
265
279
|
|
|
266
|
-
**-per33** — (
|
|
280
|
+
**-per33** — (Default: 0.03) Percentage of 3-3 cross-links; all other cross-links will be 3-4.
|
|
267
281
|
|
|
268
|
-
**-oper** — (
|
|
282
|
+
**-oper** — (Default: 1) Percentage chance of a monomer linking with an oligomer. (Actual chance of link is `cper * oper`.)
|
|
269
283
|
|
|
270
284
|
**-gdist** — (Default: 0.75,4,8.9,0.25,10,45) Distribution of glycan strand lengths. Format as `weight1,stddev1,mean1,weight2,...` where each triple describes a Gaussian. The sum of these Gaussians forms the distribution.
|
|
271
285
|
|
|
272
286
|
#### Protein options
|
|
273
287
|
|
|
274
|
-
**-fudge** — (Default: 0.3) Fudge factor for allowing lipid-protein overlap.
|
|
288
|
+
**-fudge** — (Default: 0.3) Fudge factor for allowing lipid-protein overlap. A value of 0.15 is recommended when using `-def`.
|
|
275
289
|
|
|
276
290
|
#### Solvent options
|
|
277
291
|
|
|
278
292
|
**-sol** — (Required) Solvent type.
|
|
279
293
|
|
|
280
|
-
**-sold** — (Default: 0.5) Solvent
|
|
294
|
+
**-sold** — (Default: 0.5) Solvent diameter.
|
|
281
295
|
|
|
282
296
|
**-solr** — (Default: 0.1) Magnitude of random deviations to solvent positions.
|
|
283
297
|
|
|
@@ -331,7 +345,7 @@ More detailed tutorials are available [here](Insane4MemPrO_tutorials.md).
|
|
|
331
345
|
|
|
332
346
|
If your protein hasn't oriented correctly there are a number of things to try:
|
|
333
347
|
|
|
334
|
-
* Check all orientations by loading `orientations.pdb` and reviewing `
|
|
348
|
+
* Check all orientations by loading `orientations.pdb` and reviewing `orientation.txt`. The correct orientation may not be rank 1.
|
|
335
349
|
* Check `curv_potential_curve.png` to see if your protein prefers a curved membrane. If so, using `-c` will help.
|
|
336
350
|
* Check the PDB file for missing atoms or residues, which can cause the surface to be incorrectly evaluated. Missing atoms should be fixed before orientation.
|
|
337
351
|
* Using `-wb` can be helpful for diagnosing missing atoms — it writes the potential contribution of each residue as a b-factor, viewable in PyMOL.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|