biotite 0.41.2__cp312-cp312-win_amd64.whl → 1.0.1__cp312-cp312-win_amd64.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/__init__.py +2 -3
- biotite/application/__init__.py +1 -1
- biotite/application/application.py +20 -10
- biotite/application/autodock/__init__.py +1 -1
- biotite/application/autodock/app.py +74 -79
- biotite/application/blast/__init__.py +1 -1
- biotite/application/blast/alignment.py +19 -10
- biotite/application/blast/webapp.py +92 -85
- biotite/application/clustalo/__init__.py +1 -1
- biotite/application/clustalo/app.py +46 -61
- biotite/application/dssp/__init__.py +1 -1
- biotite/application/dssp/app.py +8 -11
- biotite/application/localapp.py +62 -60
- biotite/application/mafft/__init__.py +1 -1
- biotite/application/mafft/app.py +16 -22
- biotite/application/msaapp.py +78 -89
- biotite/application/muscle/__init__.py +1 -1
- biotite/application/muscle/app3.py +50 -64
- biotite/application/muscle/app5.py +23 -31
- biotite/application/sra/__init__.py +1 -1
- biotite/application/sra/app.py +64 -68
- biotite/application/tantan/__init__.py +1 -1
- biotite/application/tantan/app.py +22 -45
- biotite/application/util.py +7 -9
- biotite/application/viennarna/rnaalifold.py +34 -28
- biotite/application/viennarna/rnafold.py +24 -39
- biotite/application/viennarna/rnaplot.py +36 -21
- biotite/application/viennarna/util.py +17 -12
- biotite/application/webapp.py +13 -14
- biotite/copyable.py +13 -13
- biotite/database/__init__.py +1 -1
- biotite/database/entrez/__init__.py +1 -1
- biotite/database/entrez/check.py +2 -3
- biotite/database/entrez/dbnames.py +7 -5
- biotite/database/entrez/download.py +55 -49
- biotite/database/entrez/key.py +1 -1
- biotite/database/entrez/query.py +62 -23
- biotite/database/error.py +2 -1
- biotite/database/pubchem/__init__.py +1 -1
- biotite/database/pubchem/download.py +43 -45
- biotite/database/pubchem/error.py +2 -2
- biotite/database/pubchem/query.py +34 -31
- biotite/database/pubchem/throttle.py +3 -4
- biotite/database/rcsb/__init__.py +1 -1
- biotite/database/rcsb/download.py +44 -52
- biotite/database/rcsb/query.py +85 -80
- biotite/database/uniprot/check.py +6 -3
- biotite/database/uniprot/download.py +6 -11
- biotite/database/uniprot/query.py +115 -31
- biotite/file.py +12 -31
- biotite/sequence/__init__.py +3 -3
- biotite/sequence/align/__init__.py +2 -2
- biotite/sequence/align/alignment.py +99 -90
- biotite/sequence/align/banded.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/buckets.py +12 -10
- biotite/sequence/align/cigar.py +43 -52
- biotite/sequence/align/kmeralphabet.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/kmeralphabet.pyx +55 -51
- biotite/sequence/align/kmersimilarity.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/kmertable.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/kmertable.pyx +3 -2
- biotite/sequence/align/localgapped.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/localungapped.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/matrix.py +81 -82
- biotite/sequence/align/multiple.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/multiple.pyx +1 -1
- biotite/sequence/align/pairwise.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/permutation.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/permutation.pyx +12 -4
- biotite/sequence/align/selector.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/selector.pyx +52 -54
- biotite/sequence/align/statistics.py +32 -33
- biotite/sequence/align/tracetable.cp312-win_amd64.pyd +0 -0
- biotite/sequence/alphabet.py +51 -65
- biotite/sequence/annotation.py +78 -77
- biotite/sequence/codec.cp312-win_amd64.pyd +0 -0
- biotite/sequence/codon.py +90 -79
- biotite/sequence/graphics/__init__.py +1 -1
- biotite/sequence/graphics/alignment.py +184 -103
- biotite/sequence/graphics/colorschemes.py +10 -12
- biotite/sequence/graphics/dendrogram.py +79 -34
- biotite/sequence/graphics/features.py +133 -99
- biotite/sequence/graphics/logo.py +22 -28
- biotite/sequence/graphics/plasmid.py +229 -178
- biotite/sequence/io/fasta/__init__.py +1 -1
- biotite/sequence/io/fasta/convert.py +44 -33
- biotite/sequence/io/fasta/file.py +42 -55
- biotite/sequence/io/fastq/__init__.py +1 -1
- biotite/sequence/io/fastq/convert.py +11 -14
- biotite/sequence/io/fastq/file.py +68 -112
- biotite/sequence/io/genbank/__init__.py +2 -2
- biotite/sequence/io/genbank/annotation.py +12 -20
- biotite/sequence/io/genbank/file.py +74 -76
- biotite/sequence/io/genbank/metadata.py +74 -62
- biotite/sequence/io/genbank/sequence.py +13 -14
- biotite/sequence/io/general.py +39 -30
- biotite/sequence/io/gff/__init__.py +2 -2
- biotite/sequence/io/gff/convert.py +10 -15
- biotite/sequence/io/gff/file.py +81 -65
- biotite/sequence/phylo/__init__.py +1 -1
- biotite/sequence/phylo/nj.cp312-win_amd64.pyd +0 -0
- biotite/sequence/phylo/tree.cp312-win_amd64.pyd +0 -0
- biotite/sequence/phylo/upgma.cp312-win_amd64.pyd +0 -0
- biotite/sequence/profile.py +57 -28
- biotite/sequence/search.py +17 -15
- biotite/sequence/seqtypes.py +200 -164
- biotite/sequence/sequence.py +15 -17
- biotite/structure/__init__.py +3 -3
- biotite/structure/atoms.py +246 -236
- biotite/structure/basepairs.py +260 -271
- biotite/structure/bonds.cp312-win_amd64.pyd +0 -0
- biotite/structure/bonds.pyx +29 -32
- biotite/structure/box.py +67 -71
- biotite/structure/celllist.cp312-win_amd64.pyd +0 -0
- biotite/structure/chains.py +55 -39
- biotite/structure/charges.cp312-win_amd64.pyd +0 -0
- biotite/structure/compare.py +32 -32
- biotite/structure/density.py +13 -18
- biotite/structure/dotbracket.py +20 -22
- biotite/structure/error.py +10 -2
- biotite/structure/filter.py +83 -78
- biotite/structure/geometry.py +130 -119
- biotite/structure/graphics/atoms.py +60 -43
- biotite/structure/graphics/rna.py +81 -68
- biotite/structure/hbond.py +112 -93
- biotite/structure/info/__init__.py +0 -2
- biotite/structure/info/atoms.py +10 -11
- biotite/structure/info/bonds.py +41 -43
- biotite/structure/info/ccd.py +4 -5
- biotite/structure/info/groups.py +1 -3
- biotite/structure/info/masses.py +5 -10
- biotite/structure/info/misc.py +1 -1
- biotite/structure/info/radii.py +20 -20
- biotite/structure/info/standardize.py +15 -26
- biotite/structure/integrity.py +18 -71
- biotite/structure/io/__init__.py +3 -4
- biotite/structure/io/dcd/__init__.py +1 -1
- biotite/structure/io/dcd/file.py +22 -20
- biotite/structure/io/general.py +47 -61
- biotite/structure/io/gro/__init__.py +1 -1
- biotite/structure/io/gro/file.py +73 -72
- biotite/structure/io/mol/__init__.py +1 -1
- biotite/structure/io/mol/convert.py +8 -11
- biotite/structure/io/mol/ctab.py +37 -36
- biotite/structure/io/mol/header.py +14 -10
- biotite/structure/io/mol/mol.py +9 -53
- biotite/structure/io/mol/sdf.py +47 -50
- biotite/structure/io/netcdf/__init__.py +1 -1
- biotite/structure/io/netcdf/file.py +24 -23
- biotite/structure/io/pdb/__init__.py +1 -1
- biotite/structure/io/pdb/convert.py +32 -20
- biotite/structure/io/pdb/file.py +151 -172
- biotite/structure/io/pdb/hybrid36.cp312-win_amd64.pyd +0 -0
- biotite/structure/io/pdbqt/__init__.py +1 -1
- biotite/structure/io/pdbqt/convert.py +17 -11
- biotite/structure/io/pdbqt/file.py +128 -80
- biotite/structure/io/pdbx/__init__.py +1 -2
- biotite/structure/io/pdbx/bcif.py +36 -44
- biotite/structure/io/pdbx/cif.py +140 -110
- biotite/structure/io/pdbx/component.py +10 -16
- biotite/structure/io/pdbx/convert.py +260 -258
- biotite/structure/io/pdbx/encoding.cp312-win_amd64.pyd +0 -0
- biotite/structure/io/trajfile.py +90 -107
- biotite/structure/io/trr/__init__.py +1 -1
- biotite/structure/io/trr/file.py +12 -15
- biotite/structure/io/xtc/__init__.py +1 -1
- biotite/structure/io/xtc/file.py +11 -14
- biotite/structure/mechanics.py +9 -11
- biotite/structure/molecules.py +3 -4
- biotite/structure/pseudoknots.py +53 -67
- biotite/structure/rdf.py +23 -21
- biotite/structure/repair.py +137 -86
- biotite/structure/residues.py +26 -16
- biotite/structure/sasa.cp312-win_amd64.pyd +0 -0
- biotite/structure/{resutil.py → segments.py} +24 -23
- biotite/structure/sequence.py +10 -11
- biotite/structure/sse.py +100 -119
- biotite/structure/superimpose.py +39 -77
- biotite/structure/transform.py +97 -71
- biotite/structure/util.py +11 -13
- biotite/version.py +2 -2
- biotite/visualize.py +69 -55
- {biotite-0.41.2.dist-info → biotite-1.0.1.dist-info}/METADATA +6 -5
- biotite-1.0.1.dist-info/RECORD +322 -0
- biotite/structure/io/ctab.py +0 -72
- biotite/structure/io/mmtf/__init__.py +0 -21
- biotite/structure/io/mmtf/assembly.py +0 -214
- biotite/structure/io/mmtf/convertarray.cp312-win_amd64.pyd +0 -0
- biotite/structure/io/mmtf/convertarray.pyx +0 -341
- biotite/structure/io/mmtf/convertfile.cp312-win_amd64.pyd +0 -0
- biotite/structure/io/mmtf/convertfile.pyx +0 -501
- biotite/structure/io/mmtf/decode.cp312-win_amd64.pyd +0 -0
- biotite/structure/io/mmtf/decode.pyx +0 -152
- biotite/structure/io/mmtf/encode.cp312-win_amd64.pyd +0 -0
- biotite/structure/io/mmtf/encode.pyx +0 -183
- biotite/structure/io/mmtf/file.py +0 -233
- biotite/structure/io/npz/__init__.py +0 -20
- biotite/structure/io/npz/file.py +0 -152
- biotite/structure/io/pdbx/legacy.py +0 -267
- biotite/structure/io/tng/__init__.py +0 -13
- biotite/structure/io/tng/file.py +0 -46
- biotite/temp.py +0 -86
- biotite-0.41.2.dist-info/RECORD +0 -340
- {biotite-0.41.2.dist-info → biotite-1.0.1.dist-info}/WHEEL +0 -0
- {biotite-0.41.2.dist-info → biotite-1.0.1.dist-info}/licenses/LICENSE.rst +0 -0
biotite/structure/io/gro/file.py
CHANGED
|
@@ -6,25 +6,27 @@ __name__ = "biotite.structure.io.gro"
|
|
|
6
6
|
__author__ = "Daniel Bauer, Patrick Kunzmann"
|
|
7
7
|
__all__ = ["GROFile"]
|
|
8
8
|
|
|
9
|
-
import numpy as np
|
|
10
|
-
from ...atoms import AtomArray, AtomArrayStack
|
|
11
|
-
from ...box import is_orthogonal
|
|
12
|
-
from ....file import TextFile, InvalidFileError
|
|
13
|
-
from ...repair import infer_elements
|
|
14
|
-
from ...error import BadStructureError
|
|
15
9
|
import copy
|
|
16
10
|
from datetime import datetime
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
11
|
+
import numpy as np
|
|
12
|
+
from biotite.file import InvalidFileError, TextFile
|
|
13
|
+
from biotite.structure.atoms import AtomArray, AtomArrayStack
|
|
14
|
+
from biotite.structure.box import is_orthogonal
|
|
15
|
+
from biotite.structure.error import BadStructureError
|
|
16
|
+
from biotite.structure.repair import infer_elements
|
|
17
|
+
|
|
18
|
+
_atom_records = {
|
|
19
|
+
"res_id": (0, 5),
|
|
20
|
+
"res_name": (5, 10),
|
|
21
|
+
"atom_name": (10, 15),
|
|
22
|
+
"atom_id": (15, 20),
|
|
23
|
+
"coord_x": (20, 28),
|
|
24
|
+
"coord_y": (28, 36),
|
|
25
|
+
"coord_z": (36, 44),
|
|
26
|
+
"v_x": (44, 52),
|
|
27
|
+
"v_y": (52, 60),
|
|
28
|
+
"v_z": (60, 68),
|
|
29
|
+
}
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
class GROFile(TextFile):
|
|
@@ -48,6 +50,7 @@ class GROFile(TextFile):
|
|
|
48
50
|
>>> file.write(os.path.join(path_to_directory, "1l2y_mod.gro"))
|
|
49
51
|
|
|
50
52
|
"""
|
|
53
|
+
|
|
51
54
|
def get_model_count(self):
|
|
52
55
|
"""
|
|
53
56
|
Get the number of models contained in this GRO file.
|
|
@@ -63,7 +66,6 @@ class GROFile(TextFile):
|
|
|
63
66
|
model_count += 1
|
|
64
67
|
return model_count
|
|
65
68
|
|
|
66
|
-
|
|
67
69
|
def get_structure(self, model=None):
|
|
68
70
|
"""
|
|
69
71
|
Get an :class:`AtomArray` or :class:`AtomArrayStack` from the
|
|
@@ -91,9 +93,7 @@ class GROFile(TextFile):
|
|
|
91
93
|
"""
|
|
92
94
|
Helper function to get the indices of all atoms for a model
|
|
93
95
|
"""
|
|
94
|
-
return np.arange(
|
|
95
|
-
model_start_i+1, model_start_i+1+model_atom_counts
|
|
96
|
-
)
|
|
96
|
+
return np.arange(model_start_i + 1, model_start_i + 1 + model_atom_counts)
|
|
97
97
|
|
|
98
98
|
def set_box_dimen(box_param):
|
|
99
99
|
"""
|
|
@@ -114,33 +114,31 @@ class GROFile(TextFile):
|
|
|
114
114
|
return None
|
|
115
115
|
if len(box_param) == 3:
|
|
116
116
|
x, y, z = box_param
|
|
117
|
-
return np.array([[x,0,0], [0,y,0], [0,0,z]], dtype=float)
|
|
117
|
+
return np.array([[x, 0, 0], [0, y, 0], [0, 0, z]], dtype=float)
|
|
118
118
|
elif len(box_param) == 9:
|
|
119
119
|
x1, y2, z3, x2, x3, y1, y3, z1, z2 = box_param
|
|
120
|
-
return np.array(
|
|
121
|
-
[[x1,x2,x3], [y1,y2,y3], [z1,z2,z3]], dtype=float
|
|
122
|
-
)
|
|
120
|
+
return np.array([[x1, x2, x3], [y1, y2, y3], [z1, z2, z3]], dtype=float)
|
|
123
121
|
else:
|
|
124
122
|
raise InvalidFileError(
|
|
125
123
|
f"Invalid amount of box parameters: {len(box_param)}"
|
|
126
124
|
)
|
|
127
125
|
|
|
128
126
|
# Line indices where a new model starts
|
|
129
|
-
model_start_i = np.array(
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
model_start_i = np.array(
|
|
128
|
+
[i for i in range(len(self.lines)) if _is_int(self.lines[i])], dtype=int
|
|
129
|
+
)
|
|
132
130
|
|
|
133
131
|
# Number of atoms in each model
|
|
134
|
-
model_atom_counts = np.array(
|
|
135
|
-
[int(self.lines[i]) for i in model_start_i]
|
|
136
|
-
)
|
|
132
|
+
model_atom_counts = np.array([int(self.lines[i]) for i in model_start_i])
|
|
137
133
|
|
|
138
134
|
if model is None:
|
|
139
135
|
# Check if all models have the same length
|
|
140
136
|
if np.all(model_atom_counts != model_atom_counts[0]):
|
|
141
|
-
raise BadStructureError(
|
|
142
|
-
|
|
143
|
-
|
|
137
|
+
raise BadStructureError(
|
|
138
|
+
"The models in the file have unequal "
|
|
139
|
+
"amount of atoms, give an explicit "
|
|
140
|
+
"model instead"
|
|
141
|
+
)
|
|
144
142
|
depth = len(model_start_i)
|
|
145
143
|
length = model_atom_counts[0]
|
|
146
144
|
array = AtomArrayStack(depth, length)
|
|
@@ -159,10 +157,10 @@ class GROFile(TextFile):
|
|
|
159
157
|
f"the given model {model} does not exist"
|
|
160
158
|
)
|
|
161
159
|
|
|
162
|
-
length = model_atom_counts[model-1]
|
|
160
|
+
length = model_atom_counts[model - 1]
|
|
163
161
|
array = AtomArray(length)
|
|
164
162
|
|
|
165
|
-
annot_i = get_atom_line_i(model_start_i[model-1], length)
|
|
163
|
+
annot_i = get_atom_line_i(model_start_i[model - 1], length)
|
|
166
164
|
|
|
167
165
|
# Replace empty strings for elements with guessed types
|
|
168
166
|
# i is index in array, line_i is line index
|
|
@@ -179,27 +177,25 @@ class GROFile(TextFile):
|
|
|
179
177
|
for i, line_i in enumerate(atom_i):
|
|
180
178
|
line = self.lines[line_i]
|
|
181
179
|
# gro files use nm instead of A
|
|
182
|
-
array.coord[i,0] = float(line[20:28])*10
|
|
183
|
-
array.coord[i,1] = float(line[28:36])*10
|
|
184
|
-
array.coord[i,2] = float(line[36:44])*10
|
|
180
|
+
array.coord[i, 0] = float(line[20:28]) * 10
|
|
181
|
+
array.coord[i, 1] = float(line[28:36]) * 10
|
|
182
|
+
array.coord[i, 2] = float(line[36:44]) * 10
|
|
185
183
|
# Box is stored in last line (after coordinates)
|
|
186
184
|
box_i = atom_i[-1] + 1
|
|
187
|
-
box_param = [float(e)*10 for e in self.lines[box_i].split()]
|
|
185
|
+
box_param = [float(e) * 10 for e in self.lines[box_i].split()]
|
|
188
186
|
array.box = set_box_dimen(box_param)
|
|
189
187
|
|
|
190
188
|
elif isinstance(array, AtomArrayStack):
|
|
191
189
|
for m in range(len(model_start_i)):
|
|
192
|
-
atom_i = get_atom_line_i(
|
|
193
|
-
model_start_i[m], model_atom_counts[m]
|
|
194
|
-
)
|
|
190
|
+
atom_i = get_atom_line_i(model_start_i[m], model_atom_counts[m])
|
|
195
191
|
for i, line_i in enumerate(atom_i):
|
|
196
192
|
line = self.lines[line_i]
|
|
197
|
-
array.coord[m,i,0] = float(line[20:28])*10
|
|
198
|
-
array.coord[m,i,1] = float(line[28:36])*10
|
|
199
|
-
array.coord[m,i,2] = float(line[36:44])*10
|
|
193
|
+
array.coord[m, i, 0] = float(line[20:28]) * 10
|
|
194
|
+
array.coord[m, i, 1] = float(line[28:36]) * 10
|
|
195
|
+
array.coord[m, i, 2] = float(line[36:44]) * 10
|
|
200
196
|
# Box is stored in last line (after coordinates)
|
|
201
197
|
box_i = atom_i[-1] + 1
|
|
202
|
-
box_param = [float(e)*10 for e in self.lines[box_i].split()]
|
|
198
|
+
box_param = [float(e) * 10 for e in self.lines[box_i].split()]
|
|
203
199
|
box = set_box_dimen(box_param)
|
|
204
200
|
# Create a box in the stack if not already existing
|
|
205
201
|
# and the box is not a dummy
|
|
@@ -210,7 +206,6 @@ class GROFile(TextFile):
|
|
|
210
206
|
|
|
211
207
|
return array
|
|
212
208
|
|
|
213
|
-
|
|
214
209
|
def set_structure(self, array):
|
|
215
210
|
"""
|
|
216
211
|
Set the :class:`AtomArray` or :class:`AtomArrayStack` for the
|
|
@@ -223,6 +218,7 @@ class GROFile(TextFile):
|
|
|
223
218
|
is given, each array in the stack is saved as separate
|
|
224
219
|
model.
|
|
225
220
|
"""
|
|
221
|
+
|
|
226
222
|
def get_box_dimen(array):
|
|
227
223
|
"""
|
|
228
224
|
GRO files have the box dimensions as last line for each
|
|
@@ -253,10 +249,15 @@ class GROFile(TextFile):
|
|
|
253
249
|
else:
|
|
254
250
|
box = box / 10
|
|
255
251
|
box_elements = (
|
|
256
|
-
box[0,0],
|
|
257
|
-
box[
|
|
258
|
-
box[
|
|
259
|
-
box[
|
|
252
|
+
box[0, 0],
|
|
253
|
+
box[1, 1],
|
|
254
|
+
box[2, 2],
|
|
255
|
+
box[0, 1],
|
|
256
|
+
box[0, 2],
|
|
257
|
+
box[1, 0],
|
|
258
|
+
box[1, 2],
|
|
259
|
+
box[2, 0],
|
|
260
|
+
box[2, 1],
|
|
260
261
|
)
|
|
261
262
|
return " ".join([f"{e:>9.5f}" for e in box_elements])
|
|
262
263
|
|
|
@@ -266,17 +267,11 @@ class GROFile(TextFile):
|
|
|
266
267
|
atom_id = np.arange(1, array.array_length() + 1)
|
|
267
268
|
# Atom IDs are supported up to 99999,
|
|
268
269
|
# but negative IDs are also possible
|
|
269
|
-
gro_atom_id = np.where(
|
|
270
|
-
atom_id > 0,
|
|
271
|
-
((atom_id - 1) % 99999) + 1,
|
|
272
|
-
atom_id
|
|
273
|
-
)
|
|
270
|
+
gro_atom_id = np.where(atom_id > 0, ((atom_id - 1) % 99999) + 1, atom_id)
|
|
274
271
|
# Residue IDs are supported up to 9999,
|
|
275
272
|
# but negative IDs are also possible
|
|
276
273
|
gro_res_id = np.where(
|
|
277
|
-
array.res_id > 0,
|
|
278
|
-
((array.res_id - 1) % 99999) + 1,
|
|
279
|
-
array.res_id
|
|
274
|
+
array.res_id > 0, ((array.res_id - 1) % 99999) + 1, array.res_id
|
|
280
275
|
)
|
|
281
276
|
|
|
282
277
|
if isinstance(array, AtomArray):
|
|
@@ -290,10 +285,14 @@ class GROFile(TextFile):
|
|
|
290
285
|
fmt = "{:>5d}{:5s}{:>5s}{:>5d}{:>8.3f}{:>8.3f}{:>8.3f}"
|
|
291
286
|
for i in range(array.array_length()):
|
|
292
287
|
# gro format is in nm -> multiply coords by 10
|
|
293
|
-
self.lines[i+2] = fmt.format(
|
|
294
|
-
gro_res_id[i],
|
|
295
|
-
|
|
296
|
-
array.
|
|
288
|
+
self.lines[i + 2] = fmt.format(
|
|
289
|
+
gro_res_id[i],
|
|
290
|
+
array.res_name[i],
|
|
291
|
+
array.atom_name[i],
|
|
292
|
+
gro_atom_id[i],
|
|
293
|
+
array.coord[i, 0] / 10,
|
|
294
|
+
array.coord[i, 1] / 10,
|
|
295
|
+
array.coord[i, 2] / 10,
|
|
297
296
|
)
|
|
298
297
|
# Write box lines
|
|
299
298
|
self.lines[-1] = get_box_dimen(array)
|
|
@@ -304,10 +303,11 @@ class GROFile(TextFile):
|
|
|
304
303
|
# Therefore template lines are created
|
|
305
304
|
# which are afterwards applied for each model
|
|
306
305
|
templines = [None] * array.array_length()
|
|
307
|
-
fmt =
|
|
306
|
+
fmt = "{:>5d}{:5s}{:>5s}{:5d}"
|
|
308
307
|
for i in range(array.array_length()):
|
|
309
|
-
templines[i] = fmt.format(
|
|
310
|
-
|
|
308
|
+
templines[i] = fmt.format(
|
|
309
|
+
gro_res_id[i], array.res_name[i], array.atom_name[i], gro_atom_id[i]
|
|
310
|
+
)
|
|
311
311
|
|
|
312
312
|
for i in range(array.stack_depth()):
|
|
313
313
|
self.lines.append(
|
|
@@ -319,10 +319,11 @@ class GROFile(TextFile):
|
|
|
319
319
|
modellines = copy.copy(templines)
|
|
320
320
|
for j, line in enumerate(modellines):
|
|
321
321
|
# Insert coordinates
|
|
322
|
-
line =
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
322
|
+
line = line + "{:>8.3f}{:>8.3f}{:>8.3f}".format(
|
|
323
|
+
array.coord[i, j, 0] / 10,
|
|
324
|
+
array.coord[i, j, 1] / 10,
|
|
325
|
+
array.coord[i, j, 2] / 10,
|
|
326
|
+
)
|
|
326
327
|
modellines[j] = line
|
|
327
328
|
self.lines.extend(modellines)
|
|
328
329
|
self.lines.append(get_box_dimen(array[i]))
|
|
@@ -340,4 +341,4 @@ def _is_int(string):
|
|
|
340
341
|
int(string)
|
|
341
342
|
return True
|
|
342
343
|
except ValueError:
|
|
343
|
-
return False
|
|
344
|
+
return False
|
|
@@ -6,9 +6,9 @@ __name__ = "biotite.structure.io.mol"
|
|
|
6
6
|
__author__ = "Patrick Kunzmann"
|
|
7
7
|
__all__ = ["get_structure", "set_structure"]
|
|
8
8
|
|
|
9
|
-
from .
|
|
10
|
-
from .
|
|
11
|
-
from
|
|
9
|
+
from biotite.structure.bonds import BondType
|
|
10
|
+
from biotite.structure.io.mol.mol import MOLFile
|
|
11
|
+
from biotite.structure.io.mol.sdf import SDFile, SDRecord
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def get_structure(mol_file, record_name=None):
|
|
@@ -39,8 +39,9 @@ def get_structure(mol_file, record_name=None):
|
|
|
39
39
|
return record.get_structure()
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def set_structure(
|
|
43
|
-
|
|
42
|
+
def set_structure(
|
|
43
|
+
mol_file, atoms, default_bond_type=BondType.ANY, version=None, record_name=None
|
|
44
|
+
):
|
|
44
45
|
"""
|
|
45
46
|
Set the :class:`AtomArray` for the MOL file.
|
|
46
47
|
|
|
@@ -88,9 +89,7 @@ def _get_record(file, record_name):
|
|
|
88
89
|
else:
|
|
89
90
|
return file[record_name]
|
|
90
91
|
else:
|
|
91
|
-
raise TypeError(
|
|
92
|
-
f"Unsupported file type '{type(file).__name__}'"
|
|
93
|
-
)
|
|
92
|
+
raise TypeError(f"Unsupported file type '{type(file).__name__}'")
|
|
94
93
|
|
|
95
94
|
|
|
96
95
|
def _get_or_create_record(file, record_name):
|
|
@@ -110,6 +109,4 @@ def _get_or_create_record(file, record_name):
|
|
|
110
109
|
file[record_name] = record
|
|
111
110
|
return file[record_name]
|
|
112
111
|
else:
|
|
113
|
-
raise TypeError(
|
|
114
|
-
f"Unsupported file type '{type(file).__name__}'"
|
|
115
|
-
)
|
|
112
|
+
raise TypeError(f"Unsupported file type '{type(file).__name__}'")
|
biotite/structure/io/mol/ctab.py
CHANGED
|
@@ -12,13 +12,13 @@ __author__ = "Patrick Kunzmann"
|
|
|
12
12
|
__all__ = ["read_structure_from_ctab", "write_structure_to_ctab"]
|
|
13
13
|
|
|
14
14
|
import itertools
|
|
15
|
-
import warnings
|
|
16
15
|
import shlex
|
|
16
|
+
import warnings
|
|
17
17
|
import numpy as np
|
|
18
|
-
from
|
|
19
|
-
from
|
|
20
|
-
from
|
|
21
|
-
from
|
|
18
|
+
from biotite.file import InvalidFileError
|
|
19
|
+
from biotite.structure.atoms import AtomArray, AtomArrayStack
|
|
20
|
+
from biotite.structure.bonds import BondList, BondType
|
|
21
|
+
from biotite.structure.error import BadStructureError
|
|
22
22
|
|
|
23
23
|
BOND_TYPE_MAPPING = {
|
|
24
24
|
1: BondType.SINGLE,
|
|
@@ -84,8 +84,7 @@ def read_structure_from_ctab(ctab_lines):
|
|
|
84
84
|
raise InvalidFileError(f"Unknown CTAB version '{unkown_version}'")
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
def write_structure_to_ctab(atoms, default_bond_type=BondType.ANY,
|
|
88
|
-
version=None):
|
|
87
|
+
def write_structure_to_ctab(atoms, default_bond_type=BondType.ANY, version=None):
|
|
89
88
|
"""
|
|
90
89
|
Convert an :class:`AtomArray` into a
|
|
91
90
|
*MDL* connection table (Ctab).
|
|
@@ -124,8 +123,7 @@ def write_structure_to_ctab(atoms, default_bond_type=BondType.ANY,
|
|
|
124
123
|
"""
|
|
125
124
|
if isinstance(atoms, AtomArrayStack):
|
|
126
125
|
raise TypeError(
|
|
127
|
-
"An 'AtomArrayStack' was given, "
|
|
128
|
-
"but only a single model can be written"
|
|
126
|
+
"An 'AtomArrayStack' was given, " "but only a single model can be written"
|
|
129
127
|
)
|
|
130
128
|
if atoms.bonds is None:
|
|
131
129
|
raise BadStructureError("Input AtomArray has no associated BondList")
|
|
@@ -134,9 +132,7 @@ def write_structure_to_ctab(atoms, default_bond_type=BondType.ANY,
|
|
|
134
132
|
|
|
135
133
|
match version:
|
|
136
134
|
case None:
|
|
137
|
-
if _is_v2000_compatible(
|
|
138
|
-
atoms.array_length(), atoms.bonds.get_bond_count()
|
|
139
|
-
):
|
|
135
|
+
if _is_v2000_compatible(atoms.array_length(), atoms.bonds.get_bond_count()):
|
|
140
136
|
return _write_structure_to_ctab_v2000(atoms, default_bond_type)
|
|
141
137
|
else:
|
|
142
138
|
return _write_structure_to_ctab_v3000(atoms, default_bond_type)
|
|
@@ -160,7 +156,8 @@ def _read_structure_from_ctab_v2000(ctab_lines):
|
|
|
160
156
|
atom_lines = ctab_lines[1 : 1 + n_atoms]
|
|
161
157
|
bond_lines = ctab_lines[1 + n_atoms : 1 + n_atoms + n_bonds]
|
|
162
158
|
charge_lines = [
|
|
163
|
-
line
|
|
159
|
+
line
|
|
160
|
+
for line in ctab_lines[1 + n_atoms + n_bonds :]
|
|
164
161
|
if line.startswith("M CHG")
|
|
165
162
|
]
|
|
166
163
|
|
|
@@ -208,10 +205,9 @@ def _read_structure_from_ctab_v2000(ctab_lines):
|
|
|
208
205
|
|
|
209
206
|
return atoms
|
|
210
207
|
|
|
208
|
+
|
|
211
209
|
def _read_structure_from_ctab_v3000(ctab_lines):
|
|
212
|
-
v30_lines = [
|
|
213
|
-
line[6:].strip() for line in ctab_lines if line.startswith("M V30")
|
|
214
|
-
]
|
|
210
|
+
v30_lines = [line[6:].strip() for line in ctab_lines if line.startswith("M V30")]
|
|
215
211
|
|
|
216
212
|
atom_lines = _get_block_v3000(v30_lines, "ATOM")
|
|
217
213
|
if len(atom_lines) == 0:
|
|
@@ -262,16 +258,20 @@ def _read_structure_from_ctab_v3000(ctab_lines):
|
|
|
262
258
|
|
|
263
259
|
return atoms
|
|
264
260
|
|
|
261
|
+
|
|
265
262
|
def _get_version(counts_line):
|
|
266
263
|
return counts_line[33:39].strip()
|
|
267
264
|
|
|
265
|
+
|
|
268
266
|
def _is_v2000_compatible(n_atoms, n_bonds):
|
|
269
267
|
# The format uses a maximum of 3 digits for the atom and bond count
|
|
270
268
|
return n_atoms < 1000 and n_bonds < 1000
|
|
271
269
|
|
|
270
|
+
|
|
272
271
|
def _get_counts_v2000(counts_line):
|
|
273
272
|
return int(counts_line[0:3]), int(counts_line[3:6])
|
|
274
273
|
|
|
274
|
+
|
|
275
275
|
def _get_block_v3000(v30_lines, block_name):
|
|
276
276
|
block_lines = []
|
|
277
277
|
in_block = False
|
|
@@ -282,13 +282,12 @@ def _get_block_v3000(v30_lines, block_name):
|
|
|
282
282
|
if in_block:
|
|
283
283
|
return block_lines
|
|
284
284
|
else:
|
|
285
|
-
raise InvalidFileError(
|
|
286
|
-
f"Block '{block_name}' ended before it began"
|
|
287
|
-
)
|
|
285
|
+
raise InvalidFileError(f"Block '{block_name}' ended before it began")
|
|
288
286
|
elif in_block:
|
|
289
287
|
block_lines.append(line)
|
|
290
288
|
return block_lines
|
|
291
289
|
|
|
290
|
+
|
|
292
291
|
def create_property_dict_v3000(property_strings):
|
|
293
292
|
properties = {}
|
|
294
293
|
for prop in property_strings:
|
|
@@ -315,7 +314,8 @@ def _write_structure_to_ctab_v2000(atoms, default_bond_type):
|
|
|
315
314
|
f" {atoms.element[i].capitalize():3}"
|
|
316
315
|
f"{0:>2}" # Mass difference -> unused
|
|
317
316
|
f"{CHARGE_MAPPING_REV.get(charge[i], 0):>3d}"
|
|
318
|
-
+ f"{0:>3d}"
|
|
317
|
+
+ f"{0:>3d}"
|
|
318
|
+
* 10 # More unused fields
|
|
319
319
|
for i in range(atoms.array_length())
|
|
320
320
|
]
|
|
321
321
|
|
|
@@ -323,7 +323,8 @@ def _write_structure_to_ctab_v2000(atoms, default_bond_type):
|
|
|
323
323
|
bond_lines = [
|
|
324
324
|
f"{i+1:>3d}{j+1:>3d}"
|
|
325
325
|
f"{BOND_TYPE_MAPPING_REV.get(bond_type, default_bond_value):>3d}"
|
|
326
|
-
+ f"{0:>3d}"
|
|
326
|
+
+ f"{0:>3d}"
|
|
327
|
+
* 4
|
|
327
328
|
for i, j, bond_type in atoms.bonds.as_array()
|
|
328
329
|
]
|
|
329
330
|
|
|
@@ -332,8 +333,7 @@ def _write_structure_to_ctab_v2000(atoms, default_bond_type):
|
|
|
332
333
|
charge_lines = []
|
|
333
334
|
# Each `M CHG` line can contain up to 8 charges
|
|
334
335
|
for batch in _batched(
|
|
335
|
-
[(atom_i, c) for atom_i, c in enumerate(charge) if c != 0],
|
|
336
|
-
N_CHARGES_PER_LINE
|
|
336
|
+
[(atom_i, c) for atom_i, c in enumerate(charge) if c != 0], N_CHARGES_PER_LINE
|
|
337
337
|
):
|
|
338
338
|
charge_lines.append(
|
|
339
339
|
f"M CHG{len(batch):>3d}"
|
|
@@ -349,9 +349,7 @@ def _write_structure_to_ctab_v3000(atoms, default_bond_type):
|
|
|
349
349
|
except AttributeError:
|
|
350
350
|
charges = np.zeros(atoms.array_length(), dtype=int)
|
|
351
351
|
|
|
352
|
-
counts_line = (
|
|
353
|
-
f"COUNTS {atoms.array_length()} {atoms.bonds.get_bond_count()} 0 0 0"
|
|
354
|
-
)
|
|
352
|
+
counts_line = f"COUNTS {atoms.array_length()} {atoms.bonds.get_bond_count()} 0 0 0"
|
|
355
353
|
|
|
356
354
|
atom_lines = [
|
|
357
355
|
f"{i + 1}"
|
|
@@ -375,32 +373,35 @@ def _write_structure_to_ctab_v3000(atoms, default_bond_type):
|
|
|
375
373
|
]
|
|
376
374
|
|
|
377
375
|
lines = (
|
|
378
|
-
["BEGIN CTAB"]
|
|
379
|
-
[counts_line]
|
|
380
|
-
["BEGIN ATOM"]
|
|
381
|
-
atom_lines
|
|
382
|
-
["END ATOM"]
|
|
383
|
-
["BEGIN BOND"]
|
|
384
|
-
bond_lines
|
|
385
|
-
["END BOND"]
|
|
386
|
-
["END CTAB"]
|
|
376
|
+
["BEGIN CTAB"]
|
|
377
|
+
+ [counts_line]
|
|
378
|
+
+ ["BEGIN ATOM"]
|
|
379
|
+
+ atom_lines
|
|
380
|
+
+ ["END ATOM"]
|
|
381
|
+
+ ["BEGIN BOND"]
|
|
382
|
+
+ bond_lines
|
|
383
|
+
+ ["END BOND"]
|
|
384
|
+
+ ["END CTAB"]
|
|
387
385
|
)
|
|
388
386
|
# Mark lines as V3000 CTAB
|
|
389
387
|
lines = ["M V30 " + line for line in lines]
|
|
390
388
|
return [V2000_COMPATIBILITY_LINE] + lines + ["M END"]
|
|
391
389
|
|
|
390
|
+
|
|
392
391
|
def _to_property(charge):
|
|
393
392
|
if charge == 0:
|
|
394
393
|
return ""
|
|
395
394
|
else:
|
|
396
395
|
return f"CHG={charge}"
|
|
397
396
|
|
|
397
|
+
|
|
398
398
|
def _quote(string):
|
|
399
399
|
if " " in string or len(string) == 0:
|
|
400
400
|
return f'"{string}"'
|
|
401
401
|
else:
|
|
402
402
|
return string
|
|
403
403
|
|
|
404
|
+
|
|
404
405
|
def _batched(iterable, n):
|
|
405
406
|
"""
|
|
406
407
|
Equivalent to :func:`itertools.batched()`.
|
|
@@ -411,4 +412,4 @@ def _batched(iterable, n):
|
|
|
411
412
|
"""
|
|
412
413
|
iterator = iter(iterable)
|
|
413
414
|
while batch := tuple(itertools.islice(iterator, n)):
|
|
414
|
-
yield batch
|
|
415
|
+
yield batch
|
|
@@ -6,16 +6,15 @@ __name__ = "biotite.structure.io.mol"
|
|
|
6
6
|
__author__ = "Patrick Kunzmann"
|
|
7
7
|
__all__ = ["Header"]
|
|
8
8
|
|
|
9
|
-
import warnings
|
|
10
9
|
import datetime
|
|
10
|
+
import warnings
|
|
11
11
|
from dataclasses import dataclass
|
|
12
12
|
|
|
13
|
-
|
|
14
13
|
_DATE_FORMAT = "%m%d%y%H%M"
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
@dataclass
|
|
18
|
-
class Header
|
|
17
|
+
class Header:
|
|
19
18
|
"""
|
|
20
19
|
The header for connection tables.
|
|
21
20
|
|
|
@@ -70,20 +69,25 @@ class Header():
|
|
|
70
69
|
try:
|
|
71
70
|
time = datetime.datetime.strptime(time_string, _DATE_FORMAT)
|
|
72
71
|
except ValueError:
|
|
73
|
-
warnings.warn(
|
|
74
|
-
f"Invalid time format '{time_string}' in file header"
|
|
75
|
-
)
|
|
72
|
+
warnings.warn(f"Invalid time format '{time_string}' in file header")
|
|
76
73
|
time = None
|
|
77
74
|
dimensions = lines[1][20:22].strip()
|
|
78
75
|
scaling_factors = lines[1][22:34].strip()
|
|
79
|
-
energy
|
|
76
|
+
energy = lines[1][34:46].strip()
|
|
80
77
|
registry_number = lines[1][46:52].strip()
|
|
81
78
|
|
|
82
79
|
comments = lines[2].strip()
|
|
83
80
|
|
|
84
81
|
return Header(
|
|
85
|
-
mol_name,
|
|
86
|
-
|
|
82
|
+
mol_name,
|
|
83
|
+
initials,
|
|
84
|
+
program,
|
|
85
|
+
time,
|
|
86
|
+
dimensions,
|
|
87
|
+
scaling_factors,
|
|
88
|
+
energy,
|
|
89
|
+
registry_number,
|
|
90
|
+
comments,
|
|
87
91
|
)
|
|
88
92
|
|
|
89
93
|
def serialize(self):
|
|
@@ -113,4 +117,4 @@ class Header():
|
|
|
113
117
|
return text
|
|
114
118
|
|
|
115
119
|
def __str__(self):
|
|
116
|
-
return self.serialize()
|
|
120
|
+
return self.serialize()
|