biotite 1.1.0__cp311-cp311-macosx_11_0_arm64.whl → 1.3.0__cp311-cp311-macosx_11_0_arm64.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.
Potentially problematic release.
This version of biotite might be problematic. Click here for more details.
- biotite/application/application.py +3 -3
- biotite/application/autodock/app.py +1 -1
- biotite/application/blast/webapp.py +1 -1
- biotite/application/clustalo/app.py +1 -1
- biotite/application/localapp.py +2 -2
- biotite/application/msaapp.py +10 -10
- biotite/application/muscle/app3.py +3 -3
- biotite/application/muscle/app5.py +3 -3
- biotite/application/sra/app.py +0 -5
- biotite/application/util.py +21 -1
- biotite/application/viennarna/rnaalifold.py +8 -8
- biotite/application/viennarna/rnaplot.py +10 -8
- biotite/application/viennarna/util.py +1 -1
- biotite/application/webapp.py +1 -1
- biotite/database/afdb/__init__.py +12 -0
- biotite/database/afdb/download.py +191 -0
- biotite/database/entrez/dbnames.py +10 -0
- biotite/database/entrez/download.py +9 -10
- biotite/database/entrez/key.py +1 -1
- biotite/database/entrez/query.py +5 -4
- biotite/database/pubchem/download.py +6 -6
- biotite/database/pubchem/error.py +10 -0
- biotite/database/pubchem/query.py +12 -23
- biotite/database/rcsb/download.py +3 -2
- biotite/database/rcsb/query.py +2 -3
- biotite/database/uniprot/check.py +2 -2
- biotite/database/uniprot/download.py +2 -5
- biotite/database/uniprot/query.py +3 -4
- biotite/file.py +14 -2
- biotite/interface/__init__.py +19 -0
- biotite/interface/openmm/__init__.py +20 -0
- biotite/interface/openmm/state.py +93 -0
- biotite/interface/openmm/system.py +227 -0
- biotite/interface/pymol/__init__.py +201 -0
- biotite/interface/pymol/cgo.py +346 -0
- biotite/interface/pymol/convert.py +185 -0
- biotite/interface/pymol/display.py +267 -0
- biotite/interface/pymol/object.py +1226 -0
- biotite/interface/pymol/shapes.py +178 -0
- biotite/interface/pymol/startup.py +169 -0
- biotite/interface/rdkit/__init__.py +19 -0
- biotite/interface/rdkit/mol.py +490 -0
- biotite/interface/version.py +94 -0
- biotite/interface/warning.py +19 -0
- biotite/sequence/align/__init__.py +0 -4
- biotite/sequence/align/alignment.py +33 -11
- biotite/sequence/align/banded.cpython-311-darwin.so +0 -0
- biotite/sequence/align/banded.pyx +22 -22
- biotite/sequence/align/cigar.py +2 -2
- biotite/sequence/align/kmeralphabet.cpython-311-darwin.so +0 -0
- biotite/sequence/align/kmeralphabet.pyx +2 -2
- biotite/sequence/align/kmersimilarity.cpython-311-darwin.so +0 -0
- biotite/sequence/align/kmertable.cpython-311-darwin.so +0 -0
- biotite/sequence/align/kmertable.pyx +6 -6
- biotite/sequence/align/localgapped.cpython-311-darwin.so +0 -0
- biotite/sequence/align/localgapped.pyx +47 -47
- biotite/sequence/align/localungapped.cpython-311-darwin.so +0 -0
- biotite/sequence/align/localungapped.pyx +10 -10
- biotite/sequence/align/matrix.py +12 -3
- biotite/sequence/align/multiple.cpython-311-darwin.so +0 -0
- biotite/sequence/align/multiple.pyx +1 -2
- biotite/sequence/align/pairwise.cpython-311-darwin.so +0 -0
- biotite/sequence/align/pairwise.pyx +37 -39
- biotite/sequence/align/permutation.cpython-311-darwin.so +0 -0
- biotite/sequence/align/selector.cpython-311-darwin.so +0 -0
- biotite/sequence/align/selector.pyx +2 -2
- biotite/sequence/align/statistics.py +1 -1
- biotite/sequence/align/tracetable.cpython-311-darwin.so +0 -0
- biotite/sequence/alphabet.py +2 -2
- biotite/sequence/annotation.py +19 -13
- biotite/sequence/codec.cpython-311-darwin.so +0 -0
- biotite/sequence/codon.py +1 -2
- biotite/sequence/graphics/alignment.py +25 -39
- biotite/sequence/graphics/dendrogram.py +4 -2
- biotite/sequence/graphics/features.py +2 -2
- biotite/sequence/graphics/logo.py +10 -12
- biotite/sequence/io/fasta/convert.py +1 -2
- biotite/sequence/io/fasta/file.py +1 -1
- biotite/sequence/io/fastq/file.py +3 -3
- biotite/sequence/io/genbank/file.py +3 -3
- biotite/sequence/io/genbank/sequence.py +2 -0
- biotite/sequence/io/gff/convert.py +1 -1
- biotite/sequence/io/gff/file.py +1 -2
- biotite/sequence/phylo/nj.cpython-311-darwin.so +0 -0
- biotite/sequence/phylo/tree.cpython-311-darwin.so +0 -0
- biotite/sequence/phylo/upgma.cpython-311-darwin.so +0 -0
- biotite/sequence/profile.py +19 -25
- biotite/sequence/search.py +0 -1
- biotite/sequence/seqtypes.py +12 -5
- biotite/sequence/sequence.py +1 -2
- biotite/structure/__init__.py +2 -0
- biotite/structure/alphabet/i3d.py +1 -2
- biotite/structure/alphabet/pb.py +1 -2
- biotite/structure/alphabet/unkerasify.py +8 -2
- biotite/structure/atoms.py +35 -27
- biotite/structure/basepairs.py +39 -40
- biotite/structure/bonds.cpython-311-darwin.so +0 -0
- biotite/structure/bonds.pyx +8 -5
- biotite/structure/box.py +159 -23
- biotite/structure/celllist.cpython-311-darwin.so +0 -0
- biotite/structure/celllist.pyx +83 -68
- biotite/structure/chains.py +17 -55
- biotite/structure/charges.cpython-311-darwin.so +0 -0
- biotite/structure/compare.py +420 -13
- biotite/structure/density.py +1 -1
- biotite/structure/dotbracket.py +31 -32
- biotite/structure/filter.py +8 -8
- biotite/structure/geometry.py +15 -15
- biotite/structure/graphics/rna.py +19 -16
- biotite/structure/hbond.py +18 -21
- biotite/structure/info/atoms.py +11 -2
- biotite/structure/info/ccd.py +0 -2
- biotite/structure/info/components.bcif +0 -0
- biotite/structure/info/groups.py +0 -3
- biotite/structure/info/misc.py +0 -1
- biotite/structure/info/radii.py +92 -22
- biotite/structure/info/standardize.py +1 -2
- biotite/structure/integrity.py +4 -6
- biotite/structure/io/general.py +2 -2
- biotite/structure/io/gro/file.py +8 -9
- biotite/structure/io/mol/convert.py +1 -1
- biotite/structure/io/mol/ctab.py +33 -28
- biotite/structure/io/mol/mol.py +1 -1
- biotite/structure/io/mol/sdf.py +39 -13
- biotite/structure/io/pdb/convert.py +86 -5
- biotite/structure/io/pdb/file.py +90 -24
- biotite/structure/io/pdb/hybrid36.cpython-311-darwin.so +0 -0
- biotite/structure/io/pdbqt/file.py +4 -4
- biotite/structure/io/pdbx/bcif.py +22 -7
- biotite/structure/io/pdbx/cif.py +20 -7
- biotite/structure/io/pdbx/component.py +6 -0
- biotite/structure/io/pdbx/compress.py +71 -34
- biotite/structure/io/pdbx/convert.py +429 -77
- biotite/structure/io/pdbx/encoding.cpython-311-darwin.so +0 -0
- biotite/structure/io/pdbx/encoding.pyx +39 -23
- biotite/structure/io/trajfile.py +9 -6
- biotite/structure/io/util.py +38 -0
- biotite/structure/mechanics.py +0 -1
- biotite/structure/molecules.py +0 -15
- biotite/structure/pseudoknots.py +13 -19
- biotite/structure/repair.py +2 -4
- biotite/structure/residues.py +20 -48
- biotite/structure/rings.py +335 -0
- biotite/structure/sasa.cpython-311-darwin.so +0 -0
- biotite/structure/sasa.pyx +30 -30
- biotite/structure/segments.py +123 -9
- biotite/structure/sequence.py +0 -1
- biotite/structure/spacegroups.json +1567 -0
- biotite/structure/spacegroups.license +26 -0
- biotite/structure/sse.py +0 -2
- biotite/structure/superimpose.py +75 -253
- biotite/structure/tm.py +581 -0
- biotite/structure/transform.py +232 -26
- biotite/structure/util.py +3 -3
- biotite/version.py +9 -4
- biotite/visualize.py +111 -1
- {biotite-1.1.0.dist-info → biotite-1.3.0.dist-info}/METADATA +8 -36
- {biotite-1.1.0.dist-info → biotite-1.3.0.dist-info}/RECORD +160 -138
- {biotite-1.1.0.dist-info → biotite-1.3.0.dist-info}/WHEEL +3 -1
- {biotite-1.1.0.dist-info → biotite-1.3.0.dist-info}/licenses/LICENSE.rst +0 -0
|
@@ -41,22 +41,22 @@ def fetch(
|
|
|
41
41
|
to be downloaded.
|
|
42
42
|
format : {'sdf', 'asnt' 'asnb', 'xml', 'json', 'jsonp', 'png'}
|
|
43
43
|
The format of the files to be downloaded.
|
|
44
|
+
target_path : str, optional
|
|
45
|
+
The target directory of the downloaded files.
|
|
46
|
+
By default, the file content is stored in a file-like object
|
|
47
|
+
(:class:`StringIO` or :class:`BytesIO`, respectively).
|
|
44
48
|
as_structural_formula : bool, optional
|
|
45
49
|
If set to true, the structural formula is download instead of
|
|
46
50
|
an 3D conformer.
|
|
47
51
|
This means that coordinates lie in th xy-plane and represent
|
|
48
52
|
the positions atoms would have an a structural formula
|
|
49
53
|
representation.
|
|
50
|
-
target_path : str, optional
|
|
51
|
-
The target directory of the downloaded files.
|
|
52
|
-
By default, the file content is stored in a file-like object
|
|
53
|
-
(:class:`StringIO` or :class:`BytesIO`, respectively).
|
|
54
54
|
overwrite : bool, optional
|
|
55
55
|
If true, existing files will be overwritten.
|
|
56
56
|
Otherwise the respective file will only be downloaded, if the
|
|
57
57
|
file does not exist yet in the specified target directory or if
|
|
58
58
|
the file is empty.
|
|
59
|
-
verbose: bool, optional
|
|
59
|
+
verbose : bool, optional
|
|
60
60
|
If set to true, the function will output the download progress.
|
|
61
61
|
throttle_threshold : float or None, optional
|
|
62
62
|
A value between 0 and 1.
|
|
@@ -114,7 +114,7 @@ def fetch(
|
|
|
114
114
|
raise TypeError("CIDs must be given as integers, not as string")
|
|
115
115
|
# Verbose output
|
|
116
116
|
if verbose:
|
|
117
|
-
print(f"Fetching file {i+1:d} / {len(cids):d} ({cid})...", end="\r")
|
|
117
|
+
print(f"Fetching file {i + 1:d} / {len(cids):d} ({cid})...", end="\r")
|
|
118
118
|
|
|
119
119
|
# Fetch file from database
|
|
120
120
|
if target_path is not None:
|
|
@@ -11,6 +11,16 @@ def parse_error_details(response_text):
|
|
|
11
11
|
"""
|
|
12
12
|
Parse the ``Detail: ...`` or alternatively ``Message: ...`` part of
|
|
13
13
|
an error response.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
response_text : str
|
|
18
|
+
The text of the response.
|
|
19
|
+
|
|
20
|
+
Returns
|
|
21
|
+
-------
|
|
22
|
+
error_details : str
|
|
23
|
+
The error details.
|
|
14
24
|
"""
|
|
15
25
|
for message_line_indicator in ["Detail: ", "Message: "]:
|
|
16
26
|
for line in response_text.splitlines():
|
|
@@ -240,6 +240,11 @@ class FormulaQuery(Query):
|
|
|
240
240
|
The maximum number of matches that this query may return.
|
|
241
241
|
By default, the *PubChem* default value is used, which can
|
|
242
242
|
be considered unlimited.
|
|
243
|
+
|
|
244
|
+
Returns
|
|
245
|
+
-------
|
|
246
|
+
query : FormulaQuery
|
|
247
|
+
The query.
|
|
243
248
|
"""
|
|
244
249
|
element_counter = collections.Counter(atoms.element)
|
|
245
250
|
formula = ""
|
|
@@ -327,7 +332,7 @@ class StructureQuery(Query, metaclass=abc.ABCMeta):
|
|
|
327
332
|
)
|
|
328
333
|
if not query_key_found:
|
|
329
334
|
raise TypeError(
|
|
330
|
-
"Expected exactly one of 'smiles', 'smarts', 'inchi', 'sdf'
|
|
335
|
+
"Expected exactly one of 'smiles', 'smarts', 'inchi', 'sdf' or 'cid'"
|
|
331
336
|
)
|
|
332
337
|
if "number" in kwargs:
|
|
333
338
|
self._number = kwargs["number"]
|
|
@@ -348,8 +353,13 @@ class StructureQuery(Query, metaclass=abc.ABCMeta):
|
|
|
348
353
|
----------
|
|
349
354
|
atoms : AtomArray or AtomArrayStack
|
|
350
355
|
The query structure.
|
|
351
|
-
**kwargs
|
|
356
|
+
*args, **kwargs
|
|
352
357
|
See the constructor for additional options.
|
|
358
|
+
|
|
359
|
+
Returns
|
|
360
|
+
-------
|
|
361
|
+
query : StructureQuery
|
|
362
|
+
The query object.
|
|
353
363
|
"""
|
|
354
364
|
mol_file = MOLFile()
|
|
355
365
|
mol_file.set_structure(atoms)
|
|
@@ -448,26 +458,19 @@ class SuperOrSubstructureQuery(StructureQuery, metaclass=abc.ABCMeta):
|
|
|
448
458
|
be considered unlimited.
|
|
449
459
|
match_charges : bool, optional
|
|
450
460
|
If set to true, atoms must match the specified charge.
|
|
451
|
-
(Default: False)
|
|
452
461
|
match_tautomers : bool, optional
|
|
453
462
|
If set to true, allow match to tautomers of the given structure.
|
|
454
|
-
(Default: False)
|
|
455
463
|
rings_not_embedded : bool, optional
|
|
456
464
|
If set to true, rings may not be embedded in a larger system.
|
|
457
|
-
(Default: False)
|
|
458
465
|
single_double_bonds_match : bool, optional
|
|
459
466
|
If set to true, single or double bonds match aromatic bonds.
|
|
460
|
-
(Default: True)
|
|
461
467
|
chains_match_rings : bool, optional
|
|
462
468
|
If set to true, chain bonds in the query may match rings in
|
|
463
469
|
hits.
|
|
464
|
-
(Default: True)
|
|
465
470
|
strip_hydrogen : bool, optional
|
|
466
471
|
If set to true, remove any explicit hydrogens before searching.
|
|
467
|
-
(Default: False)
|
|
468
472
|
stereo : {'ignore', 'exact', 'relative', 'nonconflicting'}, optional
|
|
469
473
|
How to handle stereo.
|
|
470
|
-
(Default: 'ignore')
|
|
471
474
|
|
|
472
475
|
Notes
|
|
473
476
|
-----
|
|
@@ -528,26 +531,19 @@ class SuperstructureQuery(SuperOrSubstructureQuery):
|
|
|
528
531
|
be considered unlimited.
|
|
529
532
|
match_charges : bool, optional
|
|
530
533
|
If set to true, atoms must match the specified charge.
|
|
531
|
-
(Default: False)
|
|
532
534
|
match_tautomers : bool, optional
|
|
533
535
|
If set to true, allow match to tautomers of the given structure.
|
|
534
|
-
(Default: False)
|
|
535
536
|
rings_not_embedded : bool, optional
|
|
536
537
|
If set to true, rings may not be embedded in a larger system.
|
|
537
|
-
(Default: False)
|
|
538
538
|
single_double_bonds_match : bool, optional
|
|
539
539
|
If set to true, single or double bonds match aromatic bonds.
|
|
540
|
-
(Default: True)
|
|
541
540
|
chains_match_rings : bool, optional
|
|
542
541
|
If set to true, chain bonds in the query may match rings in
|
|
543
542
|
hits.
|
|
544
|
-
(Default: True)
|
|
545
543
|
strip_hydrogen : bool, optional
|
|
546
544
|
If set to true, remove any explicit hydrogens before searching.
|
|
547
|
-
(Default: False)
|
|
548
545
|
stereo : {'ignore', 'exact', 'relative', 'nonconflicting'}, optional
|
|
549
546
|
How to handle stereo.
|
|
550
|
-
(Default: 'ignore')
|
|
551
547
|
|
|
552
548
|
Notes
|
|
553
549
|
-----
|
|
@@ -601,26 +597,19 @@ class SubstructureQuery(SuperOrSubstructureQuery):
|
|
|
601
597
|
be considered unlimited.
|
|
602
598
|
match_charges : bool, optional
|
|
603
599
|
If set to true, atoms must match the specified charge.
|
|
604
|
-
(Default: False)
|
|
605
600
|
match_tautomers : bool, optional
|
|
606
601
|
If set to true, allow match to tautomers of the given structure.
|
|
607
|
-
(Default: False)
|
|
608
602
|
rings_not_embedded : bool, optional
|
|
609
603
|
If set to true, rings may not be embedded in a larger system.
|
|
610
|
-
(Default: False)
|
|
611
604
|
single_double_bonds_match : bool, optional
|
|
612
605
|
If set to true, single or double bonds match aromatic bonds.
|
|
613
|
-
(Default: True)
|
|
614
606
|
chains_match_rings : bool, optional
|
|
615
607
|
If set to true, chain bonds in the query may match rings in
|
|
616
608
|
hits.
|
|
617
|
-
(Default: True)
|
|
618
609
|
strip_hydrogen : bool, optional
|
|
619
610
|
If set to true, remove any explicit hydrogens before searching.
|
|
620
|
-
(Default: False)
|
|
621
611
|
stereo : {'ignore', 'exact', 'relative', 'nonconflicting'}, optional
|
|
622
612
|
How to handle stereo.
|
|
623
|
-
(Default: 'ignore')
|
|
624
613
|
|
|
625
614
|
Notes
|
|
626
615
|
-----
|
|
@@ -44,7 +44,7 @@ def fetch(pdb_ids, format, target_path=None, overwrite=False, verbose=False):
|
|
|
44
44
|
Otherwise the respective file will only be downloaded, if the
|
|
45
45
|
file does not exist yet in the specified target directory or if
|
|
46
46
|
the file is empty.
|
|
47
|
-
verbose: bool, optional
|
|
47
|
+
verbose : bool, optional
|
|
48
48
|
If set to true, the function will output the download progress.
|
|
49
49
|
|
|
50
50
|
Returns
|
|
@@ -91,7 +91,7 @@ def fetch(pdb_ids, format, target_path=None, overwrite=False, verbose=False):
|
|
|
91
91
|
for i, id in enumerate(pdb_ids):
|
|
92
92
|
# Verbose output
|
|
93
93
|
if verbose:
|
|
94
|
-
print(f"Fetching file {i+1:d} / {len(pdb_ids):d} ({id})...", end="\r")
|
|
94
|
+
print(f"Fetching file {i + 1:d} / {len(pdb_ids):d} ({id})...", end="\r")
|
|
95
95
|
|
|
96
96
|
# Fetch file from database
|
|
97
97
|
if target_path is not None:
|
|
@@ -152,6 +152,7 @@ def _assert_valid_file(response_text, pdb_id):
|
|
|
152
152
|
for err_msg in [
|
|
153
153
|
"404 Not Found",
|
|
154
154
|
"<title>RCSB Protein Data Bank Error Page</title>",
|
|
155
|
+
"<title>PDB Archive over AWS</title>",
|
|
155
156
|
"No fasta files were found.",
|
|
156
157
|
"No valid PDB IDs were submitted.",
|
|
157
158
|
]
|
biotite/database/rcsb/query.py
CHANGED
|
@@ -257,7 +257,7 @@ class FieldQuery(SingleQuery):
|
|
|
257
257
|
"exists",
|
|
258
258
|
]:
|
|
259
259
|
raise TypeError(
|
|
260
|
-
f"Constructor got an unexpected keyword argument
|
|
260
|
+
f"Constructor got an unexpected keyword argument '{self._operator}'"
|
|
261
261
|
)
|
|
262
262
|
|
|
263
263
|
# Convert dates into ISO 8601
|
|
@@ -944,8 +944,7 @@ def _initialize_query_dict(query, return_type, group_by, content_types):
|
|
|
944
944
|
if group_by is not None:
|
|
945
945
|
if not group_by.is_compatible_return_type(return_type):
|
|
946
946
|
raise ValueError(
|
|
947
|
-
f"Return type '{return_type}' is not compatible "
|
|
948
|
-
f"with the given Grouping"
|
|
947
|
+
f"Return type '{return_type}' is not compatible with the given Grouping"
|
|
949
948
|
)
|
|
950
949
|
request_options["group_by"] = group_by.get_content()
|
|
951
950
|
|
|
@@ -16,8 +16,8 @@ def assert_valid_response(response):
|
|
|
16
16
|
|
|
17
17
|
Parameters
|
|
18
18
|
----------
|
|
19
|
-
|
|
20
|
-
Status code of
|
|
19
|
+
response : Response
|
|
20
|
+
Status code of :func:`requests.get()`.
|
|
21
21
|
"""
|
|
22
22
|
if len(response.content) == 0:
|
|
23
23
|
raise RequestError("No content returned")
|
|
@@ -41,7 +41,6 @@ def fetch(ids, format, target_path=None, overwrite=False, verbose=False):
|
|
|
41
41
|
Download files from the UniProt in various formats.
|
|
42
42
|
|
|
43
43
|
Available databases are UniProtKB, UniRef and UniParc.
|
|
44
|
-
|
|
45
44
|
This function requires an internet connection.
|
|
46
45
|
|
|
47
46
|
Parameters
|
|
@@ -58,11 +57,9 @@ def fetch(ids, format, target_path=None, overwrite=False, verbose=False):
|
|
|
58
57
|
overwrite : bool, optional
|
|
59
58
|
If true, existing files will be overwritten. Otherwise the
|
|
60
59
|
respective file will only be downloaded if the file does not
|
|
61
|
-
exist yet in the specified target directory
|
|
62
|
-
|
|
63
|
-
verbose: bool, optional
|
|
60
|
+
exist yet in the specified target directory.
|
|
61
|
+
verbose : bool, optional
|
|
64
62
|
If true, the function will output the download progress.
|
|
65
|
-
(Default: False)
|
|
66
63
|
|
|
67
64
|
Returns
|
|
68
65
|
-------
|
|
@@ -50,9 +50,9 @@ class CompositeQuery(Query):
|
|
|
50
50
|
|
|
51
51
|
Parameters
|
|
52
52
|
----------
|
|
53
|
-
operator: str, {"AND", "OR", "NOT"}
|
|
53
|
+
operator : str, {"AND", "OR", "NOT"}
|
|
54
54
|
The combination operator.
|
|
55
|
-
|
|
55
|
+
query1, query2 : SimpleQuery
|
|
56
56
|
The queries to be combined.
|
|
57
57
|
"""
|
|
58
58
|
|
|
@@ -114,7 +114,7 @@ class SimpleQuery(Query):
|
|
|
114
114
|
The list of possible fields and the required search term
|
|
115
115
|
formatting can be found
|
|
116
116
|
`here <https://www.uniprot.org/help/query-fields>`_.
|
|
117
|
-
term: str
|
|
117
|
+
term : str
|
|
118
118
|
The search term.
|
|
119
119
|
"""
|
|
120
120
|
|
|
@@ -264,7 +264,6 @@ def search(query, number=500):
|
|
|
264
264
|
The search query.
|
|
265
265
|
number : int
|
|
266
266
|
The maximum number of IDs that are obtained.
|
|
267
|
-
(Default: 500)
|
|
268
267
|
|
|
269
268
|
Returns
|
|
270
269
|
-------
|
biotite/file.py
CHANGED
|
@@ -44,7 +44,7 @@ class File(Copyable, metaclass=abc.ABCMeta):
|
|
|
44
44
|
|
|
45
45
|
Returns
|
|
46
46
|
-------
|
|
47
|
-
|
|
47
|
+
file : File
|
|
48
48
|
An instance from the respective :class:`File` subclass
|
|
49
49
|
representing the parsed file.
|
|
50
50
|
"""
|
|
@@ -57,7 +57,7 @@ class File(Copyable, metaclass=abc.ABCMeta):
|
|
|
57
57
|
|
|
58
58
|
Parameters
|
|
59
59
|
----------
|
|
60
|
-
|
|
60
|
+
file : file-like object or str
|
|
61
61
|
The file to be written to.
|
|
62
62
|
Alternatively a file path can be supplied.
|
|
63
63
|
"""
|
|
@@ -207,6 +207,18 @@ def wrap_string(text, width):
|
|
|
207
207
|
|
|
208
208
|
This function simply wraps the given `text` after `width`
|
|
209
209
|
characters, ignoring sentences, whitespaces, etc.
|
|
210
|
+
|
|
211
|
+
Parameters
|
|
212
|
+
----------
|
|
213
|
+
text : str
|
|
214
|
+
The text to be wrapped.
|
|
215
|
+
width : int
|
|
216
|
+
The maximum number of characters per line.
|
|
217
|
+
|
|
218
|
+
Returns
|
|
219
|
+
-------
|
|
220
|
+
lines : list of str
|
|
221
|
+
The wrapped lines.
|
|
210
222
|
"""
|
|
211
223
|
lines = []
|
|
212
224
|
for i in range(0, len(text), width):
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# This source code is part of the Biotite package and is distributed
|
|
2
|
+
# under the 3-Clause BSD License. Please see 'LICENSE.rst' for further
|
|
3
|
+
# information.
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
This subpackage provides interfaces to other Python packages in the bioinformatics
|
|
7
|
+
ecosystem.
|
|
8
|
+
Its purpose is to convert between native Biotite objects, such as :class:`.AtomArray`
|
|
9
|
+
and :class:`.Sequence`, and the corresponding objects in the respective interfaced
|
|
10
|
+
package.
|
|
11
|
+
In contrast to :mod:`biotite.application`, where an entire application run is handled
|
|
12
|
+
under the hood, :mod:`biotite.interface` only covers the object conversion, allowing
|
|
13
|
+
for more flexibility.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
__name__ = "biotite.interface"
|
|
17
|
+
__author__ = "Patrick Kunzmann"
|
|
18
|
+
|
|
19
|
+
from .warning import *
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# This source code is part of the Biotite package and is distributed
|
|
2
|
+
# under the 3-Clause BSD License. Please see 'LICENSE.rst' for further
|
|
3
|
+
# information.
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
This subpackage provides an interface to the `OpenMM <https://openmm.org/>`_
|
|
7
|
+
molecular simulation toolkit.
|
|
8
|
+
It allows conversion between :class:`.AtomArray`/:class:`.AtomArrayStack` and
|
|
9
|
+
structure-related objects from *OpenMM*.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
__name__ = "biotite.interface.openmm"
|
|
13
|
+
__author__ = "Patrick Kunzmann"
|
|
14
|
+
|
|
15
|
+
from biotite.interface.version import require_package
|
|
16
|
+
|
|
17
|
+
require_package("openmm")
|
|
18
|
+
|
|
19
|
+
from .state import *
|
|
20
|
+
from .system import *
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
__name__ = "biotite.interface.openmm"
|
|
2
|
+
__author__ = "Patrick Kunzmann"
|
|
3
|
+
__all__ = ["from_context", "from_state", "from_states"]
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import openmm
|
|
7
|
+
import biotite.structure as struc
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def from_context(template, context):
|
|
11
|
+
"""
|
|
12
|
+
Parse the coordinates and box of the current state of an
|
|
13
|
+
:class:`openmm.openmm.Context` into an :class:`AtomArray`.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
template : AtomArray
|
|
18
|
+
This structure is used as template.
|
|
19
|
+
The output :class:`AtomArray` is equal to this template with the
|
|
20
|
+
exception of the coordinates and the box vectors.
|
|
21
|
+
context : Context
|
|
22
|
+
The coordinates are parsed from the current state of this
|
|
23
|
+
:class:`openmm.openmm.Context`.
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
atoms : AtomArray
|
|
28
|
+
The created :class:`AtomArray`.
|
|
29
|
+
"""
|
|
30
|
+
state = context.getState(getPositions=True)
|
|
31
|
+
return from_state(template, state)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def from_state(template, state):
|
|
35
|
+
"""
|
|
36
|
+
Parse the coordinates and box of the given :class:`openmm.openmm.State`
|
|
37
|
+
into an :class:`AtomArray`.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
template : AtomArray
|
|
42
|
+
This structure is used as template.
|
|
43
|
+
The output :class:`AtomArray` is equal to this template with the
|
|
44
|
+
exception of the coordinates and the box vectors.
|
|
45
|
+
state : State
|
|
46
|
+
The coordinates are parsed from this state.
|
|
47
|
+
Must be created with ``getPositions=True``.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
atoms : AtomArray
|
|
52
|
+
The created :class:`AtomArray`.
|
|
53
|
+
"""
|
|
54
|
+
coord, box = _parse_state(state)
|
|
55
|
+
atoms = template.copy()
|
|
56
|
+
atoms.coord = coord
|
|
57
|
+
atoms.box = box
|
|
58
|
+
return atoms
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def from_states(template, states):
|
|
62
|
+
"""
|
|
63
|
+
Parse the coordinates and box vectors of multiple :class:`openmm.openmm.State`
|
|
64
|
+
objects into an :class:`AtomArrayStack`.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
template : AtomArray
|
|
69
|
+
This structure is used as template.
|
|
70
|
+
The output :class:`AtomArray` is equal to this template with the
|
|
71
|
+
exception of the coordinates and the box vectors.
|
|
72
|
+
states : iterable of State
|
|
73
|
+
The coordinates are parsed from these states.
|
|
74
|
+
Must be created with ``getPositions=True``.
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
atoms : AtomArrayStack
|
|
79
|
+
The created :class:`AtomArrayStack`.
|
|
80
|
+
"""
|
|
81
|
+
coords = []
|
|
82
|
+
boxes = []
|
|
83
|
+
for state in states:
|
|
84
|
+
coord, box = _parse_state(state)
|
|
85
|
+
coords.append(coord)
|
|
86
|
+
boxes.append(box)
|
|
87
|
+
return struc.from_template(template, np.stack(coords), np.stack(boxes))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _parse_state(state):
|
|
91
|
+
coord = state.getPositions(asNumpy=True).value_in_unit(openmm.unit.angstrom)
|
|
92
|
+
box = state.getPeriodicBoxVectors(asNumpy=True).value_in_unit(openmm.unit.angstrom)
|
|
93
|
+
return coord, box
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
__name__ = "biotite.interface.openmm"
|
|
2
|
+
__author__ = "Patrick Kunzmann"
|
|
3
|
+
__all__ = ["to_system", "to_topology", "from_topology"]
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import openmm
|
|
7
|
+
import openmm.app as app
|
|
8
|
+
import openmm.unit as unit
|
|
9
|
+
import biotite.structure as struc
|
|
10
|
+
import biotite.structure.info as info
|
|
11
|
+
|
|
12
|
+
_BOND_TYPE_TO_ORDER = {
|
|
13
|
+
struc.BondType.SINGLE: 1,
|
|
14
|
+
struc.BondType.DOUBLE: 2,
|
|
15
|
+
struc.BondType.TRIPLE: 3,
|
|
16
|
+
struc.BondType.QUADRUPLE: 4,
|
|
17
|
+
struc.BondType.AROMATIC_SINGLE: 1,
|
|
18
|
+
struc.BondType.AROMATIC_DOUBLE: 2,
|
|
19
|
+
struc.BondType.AROMATIC_TRIPLE: 3,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def to_system(atoms):
|
|
24
|
+
"""
|
|
25
|
+
Create a :class:`openmm.openmm.System` from an :class:`AtomArray` or
|
|
26
|
+
:class:`AtomArrayStack`.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
atoms : AtomArray or AtomArrayStack
|
|
31
|
+
The structure to be converted.
|
|
32
|
+
The box vectors are set from the ``box`` attribute.
|
|
33
|
+
If multiple models are given the box of the first model is selected.
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
system : System
|
|
38
|
+
The created :class:`openmm.openmm.System`.
|
|
39
|
+
"""
|
|
40
|
+
system = openmm.System()
|
|
41
|
+
|
|
42
|
+
for element in atoms.element:
|
|
43
|
+
system.addParticle(info.mass(element))
|
|
44
|
+
|
|
45
|
+
if atoms.box is not None:
|
|
46
|
+
if atoms.box.ndim == 3:
|
|
47
|
+
# If an `AtomArrayStack`, the first box is chosen
|
|
48
|
+
box = atoms.box[0]
|
|
49
|
+
else:
|
|
50
|
+
box = atoms.box
|
|
51
|
+
if not _check_box_requirements(box):
|
|
52
|
+
raise struc.BadStructureError(
|
|
53
|
+
"Box does not fulfill OpenMM's requirements for periodic boxes"
|
|
54
|
+
)
|
|
55
|
+
system.setDefaultPeriodicBoxVectors(*(box * unit.angstrom))
|
|
56
|
+
|
|
57
|
+
return system
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def to_topology(atoms):
|
|
61
|
+
"""
|
|
62
|
+
Create a :class:`openmm.app.topology.Topology` from an :class:`AtomArray` or
|
|
63
|
+
:class:`AtomArrayStack`.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
atoms : AtomArray or AtomArrayStack
|
|
68
|
+
The structure to be converted.
|
|
69
|
+
An associated :class:`BondList` is required.
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
topology : Topology
|
|
74
|
+
The created :class:`openmm.app.topology.Topology`.
|
|
75
|
+
"""
|
|
76
|
+
if "atom_id" in atoms.get_annotation_categories():
|
|
77
|
+
atom_id = atoms.atom_id
|
|
78
|
+
else:
|
|
79
|
+
atom_id = np.arange(atoms.array_length()) + 1
|
|
80
|
+
|
|
81
|
+
chain_starts = struc.get_chain_starts(atoms)
|
|
82
|
+
res_starts = struc.get_residue_starts(atoms)
|
|
83
|
+
|
|
84
|
+
# Lists of chain, residue and atom objects that will be filled later
|
|
85
|
+
chain_list = []
|
|
86
|
+
residue_list = []
|
|
87
|
+
atom_list = []
|
|
88
|
+
# Each atom's index in the chain and residue list
|
|
89
|
+
chain_idx = _generate_idx(chain_starts, atoms.array_length())
|
|
90
|
+
res_idx = _generate_idx(res_starts, atoms.array_length())
|
|
91
|
+
|
|
92
|
+
topology = app.Topology()
|
|
93
|
+
|
|
94
|
+
## Add atoms
|
|
95
|
+
for start_i in chain_starts:
|
|
96
|
+
chain_list.append(topology.addChain(id=atoms.chain_id[start_i]))
|
|
97
|
+
for start_i in res_starts:
|
|
98
|
+
residue_list.append(
|
|
99
|
+
topology.addResidue(
|
|
100
|
+
name=atoms.res_name[start_i],
|
|
101
|
+
chain=chain_list[chain_idx[start_i]],
|
|
102
|
+
insertionCode=atoms.ins_code[start_i],
|
|
103
|
+
id=str(atoms.res_id[start_i]),
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
for i in np.arange(atoms.array_length()):
|
|
107
|
+
atom_list.append(
|
|
108
|
+
topology.addAtom(
|
|
109
|
+
name=atoms.atom_name[i],
|
|
110
|
+
element=app.Element.getBySymbol(atoms.element[i]),
|
|
111
|
+
residue=residue_list[res_idx[i]],
|
|
112
|
+
id=str(atom_id[start_i]),
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
## Add bonds
|
|
117
|
+
if atoms.bonds is None:
|
|
118
|
+
raise struc.BadStructureError("Input structure misses an associated BondList")
|
|
119
|
+
for atom_i, atom_j, bond_type in atoms.bonds.as_array():
|
|
120
|
+
topology.addBond(
|
|
121
|
+
atom_list[atom_i],
|
|
122
|
+
atom_list[atom_j],
|
|
123
|
+
order=_BOND_TYPE_TO_ORDER.get(bond_type),
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
## Add box
|
|
127
|
+
if atoms.box is not None:
|
|
128
|
+
if atoms.box.ndim == 3:
|
|
129
|
+
# If an `AtomArrayStack`, the first box is chosen
|
|
130
|
+
box = atoms.box[0]
|
|
131
|
+
else:
|
|
132
|
+
box = atoms.box
|
|
133
|
+
if not _check_box_requirements(box):
|
|
134
|
+
raise struc.BadStructureError(
|
|
135
|
+
"Box does not fulfill OpenMM's requirements for periodic boxes"
|
|
136
|
+
)
|
|
137
|
+
topology.setPeriodicBoxVectors(box * unit.angstrom)
|
|
138
|
+
|
|
139
|
+
return topology
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def from_topology(topology):
|
|
143
|
+
"""
|
|
144
|
+
Create a :class:`AtomArray` from a :class:`openmm.app.topology.Topology`.
|
|
145
|
+
|
|
146
|
+
Parameters
|
|
147
|
+
----------
|
|
148
|
+
topology : Topology
|
|
149
|
+
The topology to be converted.
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
-------
|
|
153
|
+
atoms : AtomArray
|
|
154
|
+
The created :class:`AtomArray`.
|
|
155
|
+
As the :class:`openmm.app.topology.Topology` does not contain atom
|
|
156
|
+
coordinates, the values of the :class:`AtomArray` ``coord``
|
|
157
|
+
are set to *NaN*.
|
|
158
|
+
|
|
159
|
+
Notes
|
|
160
|
+
-----
|
|
161
|
+
This function is especially useful for obtaining an updated
|
|
162
|
+
template, if the original topology was modified
|
|
163
|
+
(e.g. via :class:`openmm.app.modeller.Modeller`).
|
|
164
|
+
"""
|
|
165
|
+
atoms = struc.AtomArray(topology.getNumAtoms())
|
|
166
|
+
|
|
167
|
+
chain_ids = []
|
|
168
|
+
res_ids = []
|
|
169
|
+
ins_codes = []
|
|
170
|
+
res_names = []
|
|
171
|
+
atom_names = []
|
|
172
|
+
elements = []
|
|
173
|
+
for chain in topology.chains():
|
|
174
|
+
chain_id = chain.id
|
|
175
|
+
for residue in chain.residues():
|
|
176
|
+
res_name = residue.name
|
|
177
|
+
res_id = int(residue.id)
|
|
178
|
+
ins_code = residue.insertionCode
|
|
179
|
+
for atom in residue.atoms():
|
|
180
|
+
chain_ids.append(chain_id)
|
|
181
|
+
res_ids.append(res_id)
|
|
182
|
+
ins_codes.append(ins_code)
|
|
183
|
+
res_names.append(res_name)
|
|
184
|
+
atom_names.append(atom.name.upper())
|
|
185
|
+
elements.append(atom.element.symbol.upper())
|
|
186
|
+
atoms.chain_id = chain_ids
|
|
187
|
+
atoms.res_id = res_ids
|
|
188
|
+
atoms.ins_code = ins_codes
|
|
189
|
+
atoms.res_name = res_names
|
|
190
|
+
atoms.atom_name = atom_names
|
|
191
|
+
atoms.element = elements
|
|
192
|
+
atoms.hetero = ~(struc.filter_amino_acids(atoms) | struc.filter_nucleotides(atoms))
|
|
193
|
+
|
|
194
|
+
bonds = []
|
|
195
|
+
atom_to_index = {atom: i for i, atom in enumerate(topology.atoms())}
|
|
196
|
+
for bond in topology.bonds():
|
|
197
|
+
order = bond.order if bond.order is not None else struc.BondType.ANY
|
|
198
|
+
bonds.append([atom_to_index[bond.atom1], atom_to_index[bond.atom2], order])
|
|
199
|
+
atoms.bonds = struc.BondList(atoms.array_length(), np.array(bonds))
|
|
200
|
+
|
|
201
|
+
box = topology.getPeriodicBoxVectors()
|
|
202
|
+
if box is None:
|
|
203
|
+
atoms.box = None
|
|
204
|
+
else:
|
|
205
|
+
atoms.box = np.asarray(box.value_in_unit(openmm.unit.angstrom))
|
|
206
|
+
|
|
207
|
+
return atoms
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _generate_idx(starts, length):
|
|
211
|
+
# An array that is 1, at start positions and 0 everywhere else
|
|
212
|
+
start_counter = np.zeros(length, dtype=int)
|
|
213
|
+
start_counter[starts] = 1
|
|
214
|
+
# The first index should be zero -> the first start is not counted
|
|
215
|
+
start_counter[0] = 0
|
|
216
|
+
return np.cumsum(start_counter)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def _check_box_requirements(box):
|
|
220
|
+
"""
|
|
221
|
+
Return True, if the given box fulfills *OpenMM*'s requirements for
|
|
222
|
+
boxes, else otherwise.
|
|
223
|
+
|
|
224
|
+
The first vector must be on the x-axis
|
|
225
|
+
and the second vector must be on the xy-plane.
|
|
226
|
+
"""
|
|
227
|
+
return np.all(np.triu(box, k=1) == 0)
|