biotite 1.2.0__cp312-cp312-win_amd64.whl → 1.4.0__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.
- biotite/application/viennarna/rnaplot.py +7 -7
- biotite/interface/openmm/__init__.py +4 -0
- biotite/interface/pymol/__init__.py +3 -0
- biotite/interface/pymol/object.py +3 -1
- biotite/interface/rdkit/__init__.py +4 -0
- biotite/interface/rdkit/mol.py +5 -5
- biotite/interface/version.py +23 -0
- biotite/sequence/align/banded.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/banded.pyx +1 -1
- biotite/sequence/align/kmeralphabet.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/kmersimilarity.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/kmertable.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/localgapped.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/localungapped.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/multiple.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/multiple.pyx +1 -2
- biotite/sequence/align/pairwise.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/pairwise.pyx +2 -4
- biotite/sequence/align/permutation.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/selector.cp312-win_amd64.pyd +0 -0
- biotite/sequence/align/tracetable.cp312-win_amd64.pyd +0 -0
- biotite/sequence/codec.cp312-win_amd64.pyd +0 -0
- 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/structure/basepairs.py +13 -14
- biotite/structure/bonds.cp312-win_amd64.pyd +0 -0
- biotite/structure/bonds.pyx +67 -6
- biotite/structure/box.py +141 -3
- biotite/structure/celllist.cp312-win_amd64.pyd +0 -0
- biotite/structure/celllist.pyx +0 -1
- biotite/structure/chains.py +15 -21
- biotite/structure/charges.cp312-win_amd64.pyd +0 -0
- biotite/structure/compare.py +2 -0
- biotite/structure/dotbracket.py +4 -4
- biotite/structure/graphics/rna.py +19 -16
- biotite/structure/hbond.py +1 -2
- biotite/structure/info/components.bcif +0 -0
- biotite/structure/io/pdb/convert.py +84 -2
- biotite/structure/io/pdb/file.py +94 -7
- biotite/structure/io/pdb/hybrid36.cp312-win_amd64.pyd +0 -0
- biotite/structure/io/pdbx/bcif.py +6 -3
- biotite/structure/io/pdbx/cif.py +5 -2
- biotite/structure/io/pdbx/compress.py +71 -34
- biotite/structure/io/pdbx/convert.py +226 -58
- biotite/structure/io/pdbx/encoding.cp312-win_amd64.pyd +0 -0
- biotite/structure/io/pdbx/encoding.pyx +39 -23
- biotite/structure/pseudoknots.py +6 -6
- biotite/structure/residues.py +10 -27
- biotite/structure/rings.py +118 -2
- biotite/structure/sasa.cp312-win_amd64.pyd +0 -0
- biotite/structure/sasa.pyx +28 -29
- biotite/structure/segments.py +55 -0
- biotite/structure/spacegroups.json +1567 -0
- biotite/structure/spacegroups.license +26 -0
- biotite/structure/superimpose.py +1 -191
- biotite/structure/transform.py +220 -1
- biotite/version.py +2 -2
- {biotite-1.2.0.dist-info → biotite-1.4.0.dist-info}/METADATA +4 -34
- {biotite-1.2.0.dist-info → biotite-1.4.0.dist-info}/RECORD +62 -60
- {biotite-1.2.0.dist-info → biotite-1.4.0.dist-info}/WHEEL +1 -1
- {biotite-1.2.0.dist-info → biotite-1.4.0.dist-info}/licenses/LICENSE.rst +0 -0
|
@@ -28,15 +28,15 @@ class RNAplotApp(LocalApp):
|
|
|
28
28
|
|
|
29
29
|
Parameters
|
|
30
30
|
----------
|
|
31
|
-
dot_bracket : str, optional
|
|
31
|
+
dot_bracket : str, optional
|
|
32
32
|
The structure in dot bracket notation.
|
|
33
|
-
base_pairs : ndarray, shape=(n,2), optional
|
|
33
|
+
base_pairs : ndarray, shape=(n,2), optional
|
|
34
34
|
Each row corresponds to the positions of the bases in the
|
|
35
35
|
strand. This parameter is mutually exclusive to ``dot_bracket``.
|
|
36
|
-
length : int, optional
|
|
36
|
+
length : int, optional
|
|
37
37
|
The number of bases in the strand. This parameter is required if
|
|
38
38
|
``base_pairs`` is given.
|
|
39
|
-
layout_type : RNAplotApp.Layout, optional
|
|
39
|
+
layout_type : RNAplotApp.Layout, optional
|
|
40
40
|
The layout type according to the *RNAplot* documentation.
|
|
41
41
|
bin_path : str, optional
|
|
42
42
|
Path of the *RNAplot* binary.
|
|
@@ -176,13 +176,13 @@ class RNAplotApp(LocalApp):
|
|
|
176
176
|
|
|
177
177
|
Parameters
|
|
178
178
|
----------
|
|
179
|
-
dot_bracket : str, optional
|
|
179
|
+
dot_bracket : str, optional
|
|
180
180
|
The structure in dot bracket notation.
|
|
181
|
-
base_pairs : ndarray, shape=(n,2), optional
|
|
181
|
+
base_pairs : ndarray, shape=(n,2), optional
|
|
182
182
|
Each row corresponds to the positions of the bases in the
|
|
183
183
|
strand. This parameter is mutually exclusive to
|
|
184
184
|
``dot_bracket``.
|
|
185
|
-
length : int, optional
|
|
185
|
+
length : int, optional
|
|
186
186
|
The number of bases in the strand. This parameter is
|
|
187
187
|
required if ``base_pairs`` is given.
|
|
188
188
|
layout_type : Layout
|
|
@@ -12,5 +12,9 @@ structure-related objects from *OpenMM*.
|
|
|
12
12
|
__name__ = "biotite.interface.openmm"
|
|
13
13
|
__author__ = "Patrick Kunzmann"
|
|
14
14
|
|
|
15
|
+
from biotite.interface.version import require_package
|
|
16
|
+
|
|
17
|
+
require_package("openmm")
|
|
18
|
+
|
|
15
19
|
from .state import *
|
|
16
20
|
from .system import *
|
|
@@ -162,6 +162,9 @@ or ``pymol_interface.cmd`` at the required places in your code.
|
|
|
162
162
|
__name__ = "biotite.interface.pymol"
|
|
163
163
|
__author__ = "Patrick Kunzmann"
|
|
164
164
|
|
|
165
|
+
from biotite.interface.version import require_package
|
|
166
|
+
|
|
167
|
+
require_package("pymol")
|
|
165
168
|
|
|
166
169
|
from .cgo import *
|
|
167
170
|
from .convert import *
|
|
@@ -388,7 +388,9 @@ class PyMOLObject:
|
|
|
388
388
|
elif isinstance(selection, str):
|
|
389
389
|
return f"%{self._name} and ({selection})"
|
|
390
390
|
else:
|
|
391
|
-
|
|
391
|
+
if not isinstance(selection, slice):
|
|
392
|
+
selection = np.asarray(selection)
|
|
393
|
+
sel = self.where(selection)
|
|
392
394
|
if sel == "none" and not_none:
|
|
393
395
|
raise ValueError("Selection contains no atoms")
|
|
394
396
|
return sel
|
biotite/interface/rdkit/mol.py
CHANGED
|
@@ -59,7 +59,7 @@ _STANDARD_ANNOTATIONS = frozenset(
|
|
|
59
59
|
"charge",
|
|
60
60
|
"b_factor",
|
|
61
61
|
"occupancy",
|
|
62
|
-
"
|
|
62
|
+
"altloc_id",
|
|
63
63
|
}
|
|
64
64
|
)
|
|
65
65
|
|
|
@@ -202,8 +202,8 @@ def to_mol(
|
|
|
202
202
|
rdkit_atom_res_info.SetOccupancy(atoms.occupancy[i].item())
|
|
203
203
|
if "b_factor" in has_annot:
|
|
204
204
|
rdkit_atom_res_info.SetTempFactor(atoms.b_factor[i].item())
|
|
205
|
-
if "
|
|
206
|
-
rdkit_atom_res_info.SetAltLoc(atoms.
|
|
205
|
+
if "altloc_id" in has_annot:
|
|
206
|
+
rdkit_atom_res_info.SetAltLoc(atoms.altloc_id[i].item())
|
|
207
207
|
rdkit_atom.SetPDBResidueInfo(rdkit_atom_res_info)
|
|
208
208
|
|
|
209
209
|
# add extra annotations
|
|
@@ -361,7 +361,7 @@ def from_mol(mol, conformer_id=None, add_hydrogen=None):
|
|
|
361
361
|
atoms.add_annotation("charge", int)
|
|
362
362
|
atoms.add_annotation("b_factor", float)
|
|
363
363
|
atoms.add_annotation("occupancy", float)
|
|
364
|
-
atoms.add_annotation("
|
|
364
|
+
atoms.add_annotation("altloc_id", str)
|
|
365
365
|
|
|
366
366
|
for rdkit_atom in rdkit_atoms:
|
|
367
367
|
_atom_idx = rdkit_atom.GetIdx()
|
|
@@ -406,7 +406,7 @@ def from_mol(mol, conformer_id=None, add_hydrogen=None):
|
|
|
406
406
|
atoms.res_id[_atom_idx] = residue_info.GetResidueNumber()
|
|
407
407
|
atoms.ins_code[_atom_idx] = residue_info.GetInsertionCode()
|
|
408
408
|
atoms.res_name[_atom_idx] = residue_info.GetResidueName()
|
|
409
|
-
atoms.
|
|
409
|
+
atoms.altloc_id[_atom_idx] = residue_info.GetAltLoc()
|
|
410
410
|
atoms.hetero[_atom_idx] = residue_info.GetIsHeteroAtom()
|
|
411
411
|
atoms.b_factor[_atom_idx] = residue_info.GetTempFactor()
|
|
412
412
|
atoms.occupancy[_atom_idx] = residue_info.GetOccupancy()
|
biotite/interface/version.py
CHANGED
|
@@ -26,6 +26,29 @@ class VersionError(Exception):
|
|
|
26
26
|
pass
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
def require_package(package):
|
|
30
|
+
"""
|
|
31
|
+
Check if the given package is installed and raise an exception if not.
|
|
32
|
+
|
|
33
|
+
Parameters
|
|
34
|
+
----------
|
|
35
|
+
package : str
|
|
36
|
+
The name of the package to be checked.
|
|
37
|
+
|
|
38
|
+
Raises
|
|
39
|
+
------
|
|
40
|
+
ImportError
|
|
41
|
+
If the package is not installed.
|
|
42
|
+
|
|
43
|
+
Notes
|
|
44
|
+
-----
|
|
45
|
+
It is useful to call this function in the ``__init__.py`` of each ``interface``
|
|
46
|
+
subpackage, to obtain clear error messages about missing dependencies.
|
|
47
|
+
"""
|
|
48
|
+
if importlib.util.find_spec(package) is None:
|
|
49
|
+
raise ImportError(f"'{package}' is not installed")
|
|
50
|
+
|
|
51
|
+
|
|
29
52
|
def requires_version(package, version_specifier):
|
|
30
53
|
"""
|
|
31
54
|
Declare a function variant that is compatible with a specific version range of the
|
|
Binary file
|
|
@@ -76,7 +76,7 @@ def align_banded(seq1, seq2, matrix, band, gap_penalty=-10, local=False,
|
|
|
76
76
|
If a tuple is provided, an affine gap penalty is used.
|
|
77
77
|
The first integer in the tuple is the gap opening penalty,
|
|
78
78
|
the second integer is the gap extension penalty.
|
|
79
|
-
The values need to be negative.
|
|
79
|
+
The values need to be negative.
|
|
80
80
|
local : bool, optional
|
|
81
81
|
If set to true, a local alignment is performed.
|
|
82
82
|
Otherwise (default) a semi-global alignment is performed.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -92,10 +92,9 @@ def align_multiple(sequences, matrix, gap_penalty=-10, terminal_penalty=True,
|
|
|
92
92
|
penalty is used. The first integer in the tuple is the gap
|
|
93
93
|
opening penalty, the second integer is the gap extension
|
|
94
94
|
penalty.
|
|
95
|
-
The values need to be negative.
|
|
95
|
+
The values need to be negative.
|
|
96
96
|
terminal_penalty : bool, optional
|
|
97
97
|
If true, gap penalties are applied to terminal gaps.
|
|
98
|
-
(Default: True)
|
|
99
98
|
distances : ndarray, shape=(n,n)
|
|
100
99
|
Pairwise distances of the sequences.
|
|
101
100
|
The matrix must be symmetric and all entries must be larger
|
|
Binary file
|
|
@@ -138,19 +138,17 @@ def align_optimal(seq1, seq2, matrix, gap_penalty=-10,
|
|
|
138
138
|
If a tuple is provided, an affine gap penalty is used.
|
|
139
139
|
The first integer in the tuple is the gap opening penalty,
|
|
140
140
|
the second integer is the gap extension penalty.
|
|
141
|
-
The values need to be negative.
|
|
141
|
+
The values need to be negative.
|
|
142
142
|
terminal_penalty : bool, optional
|
|
143
143
|
If true, gap penalties are applied to terminal gaps.
|
|
144
144
|
If `local` is true, this parameter has no effect.
|
|
145
|
-
(Default: True)
|
|
146
145
|
local : bool, optional
|
|
147
146
|
If false, a global alignment is performed, otherwise a local
|
|
148
|
-
alignment is performed.
|
|
147
|
+
alignment is performed.
|
|
149
148
|
max_number : int, optional
|
|
150
149
|
The maximum number of alignments returned.
|
|
151
150
|
When the number of branches exceeds this value in the traceback
|
|
152
151
|
step, no further branches are created.
|
|
153
|
-
(Default: 1000)
|
|
154
152
|
|
|
155
153
|
Returns
|
|
156
154
|
-------
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
biotite/structure/basepairs.py
CHANGED
|
@@ -638,7 +638,7 @@ def base_stacking(atom_array, min_atoms_per_base=3):
|
|
|
638
638
|
----------
|
|
639
639
|
atom_array : AtomArray
|
|
640
640
|
The :class:`AtomArray` to find stacked bases in.
|
|
641
|
-
min_atoms_per_base : integer, optional
|
|
641
|
+
min_atoms_per_base : integer, optional
|
|
642
642
|
The number of atoms a nucleotides' base must have to be
|
|
643
643
|
considered a candidate for a stacking interaction.
|
|
644
644
|
|
|
@@ -783,10 +783,10 @@ def base_pairs(atom_array, min_atoms_per_base=3, unique=True):
|
|
|
783
783
|
----------
|
|
784
784
|
atom_array : AtomArray
|
|
785
785
|
The :class:`AtomArray` to find base pairs in.
|
|
786
|
-
min_atoms_per_base : integer, optional
|
|
786
|
+
min_atoms_per_base : integer, optional
|
|
787
787
|
The number of atoms a nucleotides' base must have to be
|
|
788
788
|
considered a candidate for a base pair.
|
|
789
|
-
unique : bool, optional
|
|
789
|
+
unique : bool, optional
|
|
790
790
|
If ``True``, each base is assumed to be only paired with one
|
|
791
791
|
other base. If multiple pairings are plausible, the pairing with
|
|
792
792
|
the most hydrogen bonds is selected.
|
|
@@ -1203,26 +1203,25 @@ def map_nucleotide(residue, min_atoms_per_base=3, rmsd_cutoff=0.28):
|
|
|
1203
1203
|
If a different nucleotide is given, it is mapped to the best
|
|
1204
1204
|
fitting base using the algorithm described below.
|
|
1205
1205
|
|
|
1206
|
-
(i) The number of matching atom names with the reference bases is
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
(default 3) the nucleotide cannot be mapped and ``None`` is
|
|
1206
|
+
(i) The number of matching atom names with the reference bases is counted.
|
|
1207
|
+
If the number of matching atoms with all reference bases is less than the
|
|
1208
|
+
specified `min_atoms_per_base` the nucleotide cannot be mapped and ``None`` is
|
|
1210
1209
|
returned.
|
|
1211
1210
|
|
|
1212
|
-
(ii) The bases with maximum number of matching atoms are selected
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
and ``None`` is returned.
|
|
1211
|
+
(ii) The bases with maximum number of matching atoms are selected and superimposed
|
|
1212
|
+
with each reference.
|
|
1213
|
+
The base with lowest RMSD is chosen.
|
|
1214
|
+
If the RMSD is more than the specified `rmsd_cutoff`, the nucleotide cannot be
|
|
1215
|
+
mapped and ``None`` is returned.
|
|
1217
1216
|
|
|
1218
1217
|
Parameters
|
|
1219
1218
|
----------
|
|
1220
1219
|
residue : AtomArray
|
|
1221
1220
|
The nucleotide to be mapped.
|
|
1222
|
-
min_atoms_per_base : int, optional
|
|
1221
|
+
min_atoms_per_base : int, optional
|
|
1223
1222
|
The number of atoms the residue must have in common with the
|
|
1224
1223
|
reference.
|
|
1225
|
-
rmsd_cutoff : float, optional
|
|
1224
|
+
rmsd_cutoff : float, optional
|
|
1226
1225
|
The maximum RSMD that is allowed for a mapping to occur.
|
|
1227
1226
|
|
|
1228
1227
|
Returns
|
|
Binary file
|
biotite/structure/bonds.pyx
CHANGED
|
@@ -517,14 +517,41 @@ class BondList(Copyable):
|
|
|
517
517
|
0 1 SINGLE
|
|
518
518
|
1 2 DOUBLE
|
|
519
519
|
"""
|
|
520
|
-
bond_types = self._bonds[:,2]
|
|
521
520
|
for aromatic_type, non_aromatic_type in [
|
|
522
521
|
(BondType.AROMATIC_SINGLE, BondType.SINGLE),
|
|
523
522
|
(BondType.AROMATIC_DOUBLE, BondType.DOUBLE),
|
|
524
523
|
(BondType.AROMATIC_TRIPLE, BondType.TRIPLE),
|
|
525
524
|
(BondType.AROMATIC, BondType.ANY),
|
|
526
525
|
]:
|
|
527
|
-
|
|
526
|
+
mask = self._bonds[:, 2] == aromatic_type
|
|
527
|
+
self._bonds[mask, 2] = non_aromatic_type
|
|
528
|
+
|
|
529
|
+
def remove_kekulization(self):
|
|
530
|
+
"""
|
|
531
|
+
Remove the bond order information from aromatic bonds, i.e. convert all
|
|
532
|
+
aromatic bonds to :attr:`BondType.ANY`.
|
|
533
|
+
|
|
534
|
+
Examples
|
|
535
|
+
--------
|
|
536
|
+
|
|
537
|
+
>>> bond_list = BondList(3)
|
|
538
|
+
>>> bond_list.add_bond(0, 1, BondType.AROMATIC_SINGLE)
|
|
539
|
+
>>> bond_list.add_bond(1, 2, BondType.AROMATIC_DOUBLE)
|
|
540
|
+
>>> bond_list.remove_kekulization()
|
|
541
|
+
>>> for i, j, bond_type in bond_list.as_array():
|
|
542
|
+
... print(i, j, BondType(bond_type).name)
|
|
543
|
+
0 1 AROMATIC
|
|
544
|
+
1 2 AROMATIC
|
|
545
|
+
"""
|
|
546
|
+
kekulized_mask = np.isin(
|
|
547
|
+
self._bonds[:, 2],
|
|
548
|
+
(
|
|
549
|
+
BondType.AROMATIC_SINGLE,
|
|
550
|
+
BondType.AROMATIC_DOUBLE,
|
|
551
|
+
BondType.AROMATIC_TRIPLE,
|
|
552
|
+
),
|
|
553
|
+
)
|
|
554
|
+
self._bonds[kekulized_mask, 2] = BondType.AROMATIC
|
|
528
555
|
|
|
529
556
|
def remove_bond_order(self):
|
|
530
557
|
"""
|
|
@@ -532,6 +559,41 @@ class BondList(Copyable):
|
|
|
532
559
|
"""
|
|
533
560
|
self._bonds[:,2] = BondType.ANY
|
|
534
561
|
|
|
562
|
+
def convert_bond_type(self, original_bond_type, new_bond_type):
|
|
563
|
+
"""
|
|
564
|
+
convert_bond_type(original_bond_type, new_bond_type)
|
|
565
|
+
|
|
566
|
+
Convert all occurences of a given bond type into another bond type.
|
|
567
|
+
|
|
568
|
+
Parameters
|
|
569
|
+
----------
|
|
570
|
+
original_bond_type : BondType or int
|
|
571
|
+
The bond type to convert.
|
|
572
|
+
new_bond_type : BondType or int
|
|
573
|
+
The new bond type.
|
|
574
|
+
|
|
575
|
+
Examples
|
|
576
|
+
--------
|
|
577
|
+
|
|
578
|
+
>>> bond_list = BondList(4)
|
|
579
|
+
>>> bond_list.add_bond(0, 1, BondType.DOUBLE)
|
|
580
|
+
>>> bond_list.add_bond(1, 2, BondType.COORDINATION)
|
|
581
|
+
>>> bond_list.add_bond(2, 3, BondType.COORDINATION)
|
|
582
|
+
>>> for i, j, bond_type in bond_list.as_array():
|
|
583
|
+
... print(i, j, BondType(bond_type).name)
|
|
584
|
+
0 1 DOUBLE
|
|
585
|
+
1 2 COORDINATION
|
|
586
|
+
2 3 COORDINATION
|
|
587
|
+
>>> bond_list.convert_bond_type(BondType.COORDINATION, BondType.SINGLE)
|
|
588
|
+
>>> for i, j, bond_type in bond_list.as_array():
|
|
589
|
+
... print(i, j, BondType(bond_type).name)
|
|
590
|
+
0 1 DOUBLE
|
|
591
|
+
1 2 SINGLE
|
|
592
|
+
2 3 SINGLE
|
|
593
|
+
"""
|
|
594
|
+
mask = self._bonds[:, 2] == original_bond_type
|
|
595
|
+
self._bonds[mask, 2] = new_bond_type
|
|
596
|
+
|
|
535
597
|
def get_atom_count(self):
|
|
536
598
|
"""
|
|
537
599
|
get_atom_count()
|
|
@@ -1437,9 +1499,8 @@ _DEFAULT_DISTANCE_RANGE = {
|
|
|
1437
1499
|
def connect_via_distances(atoms, dict distance_range=None, bint inter_residue=True,
|
|
1438
1500
|
default_bond_type=BondType.ANY, bint periodic=False):
|
|
1439
1501
|
"""
|
|
1440
|
-
connect_via_distances(atoms, distance_range=None,
|
|
1441
|
-
|
|
1442
|
-
periodic=False)
|
|
1502
|
+
connect_via_distances(atoms, distance_range=None, inter_residue=True,
|
|
1503
|
+
default_bond_type=BondType.ANY, periodic=False)
|
|
1443
1504
|
|
|
1444
1505
|
Create a :class:`BondList` for a given atom array, based on
|
|
1445
1506
|
pairwise atom distances.
|
|
@@ -1589,7 +1650,7 @@ def connect_via_distances(atoms, dict distance_range=None, bint inter_residue=Tr
|
|
|
1589
1650
|
def connect_via_residue_names(atoms, bint inter_residue=True,
|
|
1590
1651
|
dict custom_bond_dict=None):
|
|
1591
1652
|
"""
|
|
1592
|
-
connect_via_residue_names(atoms,
|
|
1653
|
+
connect_via_residue_names(atoms, inter_residue=True, custom_bond_dict=None)
|
|
1593
1654
|
|
|
1594
1655
|
Create a :class:`BondList` for a given atom array (stack), based on
|
|
1595
1656
|
the deposited bonds for each residue in the RCSB ``components.cif``
|
biotite/structure/box.py
CHANGED
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
"""
|
|
6
6
|
Functions related to working with the simulation box or unit cell
|
|
7
|
-
of a structure
|
|
7
|
+
of a structure.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
__name__ = "biotite.structure"
|
|
11
11
|
__author__ = "Patrick Kunzmann"
|
|
12
12
|
__all__ = [
|
|
13
|
+
"space_group_transforms",
|
|
13
14
|
"vectors_from_unitcell",
|
|
14
15
|
"unitcell_from_vectors",
|
|
15
16
|
"box_volume",
|
|
@@ -23,16 +24,127 @@ __all__ = [
|
|
|
23
24
|
"is_orthogonal",
|
|
24
25
|
]
|
|
25
26
|
|
|
27
|
+
import functools
|
|
28
|
+
import json
|
|
26
29
|
from numbers import Integral
|
|
30
|
+
from pathlib import Path
|
|
27
31
|
import numpy as np
|
|
28
32
|
import numpy.linalg as linalg
|
|
29
33
|
from biotite.structure.atoms import repeat
|
|
30
34
|
from biotite.structure.chains import get_chain_masks, get_chain_starts
|
|
31
35
|
from biotite.structure.error import BadStructureError
|
|
32
36
|
from biotite.structure.molecules import get_molecule_masks
|
|
37
|
+
from biotite.structure.transform import AffineTransformation
|
|
33
38
|
from biotite.structure.util import vector_dot
|
|
34
39
|
|
|
35
40
|
|
|
41
|
+
def space_group_transforms(space_group):
|
|
42
|
+
"""
|
|
43
|
+
Get the coordinate transformations for a given space group.
|
|
44
|
+
|
|
45
|
+
Applying each transformation to a structure (in fractional coordinates) reproduces
|
|
46
|
+
the entire unit cell.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
space_group : str or int
|
|
51
|
+
The space group name (full *Hermann-Mauguin* symbol) or
|
|
52
|
+
*International Table*'s number.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
transformations : list of AffineTransformation
|
|
57
|
+
The transformations that creates the symmetric copies of a structure in a unit
|
|
58
|
+
cell of the given space group.
|
|
59
|
+
Note that the transformations need to be applied to coordinates in fractions
|
|
60
|
+
of the unit cell and also return fractional coordinates, when applied.
|
|
61
|
+
|
|
62
|
+
See Also
|
|
63
|
+
--------
|
|
64
|
+
coord_to_fraction : Used to convert to fractional coordinates.
|
|
65
|
+
fraction_to_coord : Used to convert back to Cartesian coordinates.
|
|
66
|
+
|
|
67
|
+
Examples
|
|
68
|
+
--------
|
|
69
|
+
|
|
70
|
+
>>> transforms = space_group_transforms("P 21 21 21")
|
|
71
|
+
>>> for transform in transforms:
|
|
72
|
+
... print(transform.rotation)
|
|
73
|
+
... print(transform.target_translation)
|
|
74
|
+
... print()
|
|
75
|
+
[[[1. 0. 0.]
|
|
76
|
+
[0. 1. 0.]
|
|
77
|
+
[0. 0. 1.]]]
|
|
78
|
+
[[0. 0. 0.]]
|
|
79
|
+
<BLANKLINE>
|
|
80
|
+
[[[-1. 0. 0.]
|
|
81
|
+
[ 0. -1. 0.]
|
|
82
|
+
[ 0. 0. 1.]]]
|
|
83
|
+
[[0.5 0.0 0.5]]
|
|
84
|
+
<BLANKLINE>
|
|
85
|
+
[[[-1. 0. 0.]
|
|
86
|
+
[ 0. 1. 0.]
|
|
87
|
+
[ 0. 0. -1.]]]
|
|
88
|
+
[[0.0 0.5 0.5]]
|
|
89
|
+
<BLANKLINE>
|
|
90
|
+
[[[ 1. 0. 0.]
|
|
91
|
+
[ 0. -1. 0.]
|
|
92
|
+
[ 0. 0. -1.]]]
|
|
93
|
+
[[0.5 0.5 0.0]]
|
|
94
|
+
<BLANKLINE>
|
|
95
|
+
|
|
96
|
+
Reproduce the unit cell for some coordinates (in this case only one atom).
|
|
97
|
+
|
|
98
|
+
>>> asym_coord = np.array([[1.0, 2.0, 3.0]])
|
|
99
|
+
>>> box = np.eye(3) * 10
|
|
100
|
+
>>> transforms = space_group_transforms("P 21 21 21")
|
|
101
|
+
>>> # Apply the transformations to fractional coordinates of the asymmetric unit
|
|
102
|
+
>>> unit_cell = np.concatenate(
|
|
103
|
+
... [
|
|
104
|
+
... fraction_to_coord(transform.apply(coord_to_fraction(asym_coord, box)), box)
|
|
105
|
+
... for transform in transforms
|
|
106
|
+
... ]
|
|
107
|
+
... )
|
|
108
|
+
>>> print(unit_cell)
|
|
109
|
+
[[ 1. 2. 3.]
|
|
110
|
+
[ 4. -2. 8.]
|
|
111
|
+
[-1. 7. 2.]
|
|
112
|
+
[ 6. 3. -3.]]
|
|
113
|
+
"""
|
|
114
|
+
transformation_data = _get_transformation_data()
|
|
115
|
+
|
|
116
|
+
if isinstance(space_group, str):
|
|
117
|
+
try:
|
|
118
|
+
space_group_index = transformation_data["group_names"][space_group]
|
|
119
|
+
except KeyError:
|
|
120
|
+
raise ValueError(f"Space group '{space_group}' does not exist")
|
|
121
|
+
else:
|
|
122
|
+
try:
|
|
123
|
+
space_group_index = transformation_data["group_numbers"][str(space_group)]
|
|
124
|
+
except KeyError:
|
|
125
|
+
raise ValueError(f"Space group number {space_group} does not exist")
|
|
126
|
+
|
|
127
|
+
space_group = transformation_data["space_groups"][space_group_index]
|
|
128
|
+
transformations = []
|
|
129
|
+
for transformation_index in space_group:
|
|
130
|
+
matrix = np.zeros((3, 3), dtype=np.float32)
|
|
131
|
+
translation = np.zeros(3, dtype=np.float32)
|
|
132
|
+
for i, part_index in enumerate(
|
|
133
|
+
transformation_data["transformations"][transformation_index]
|
|
134
|
+
):
|
|
135
|
+
part = transformation_data["transformation_parts"][part_index]
|
|
136
|
+
matrix[i, :] = part[:3]
|
|
137
|
+
translation[i] = part[3]
|
|
138
|
+
transformations.append(
|
|
139
|
+
AffineTransformation(
|
|
140
|
+
center_translation=np.zeros(3, dtype=np.float32),
|
|
141
|
+
rotation=matrix,
|
|
142
|
+
target_translation=translation,
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
return transformations
|
|
146
|
+
|
|
147
|
+
|
|
36
148
|
def vectors_from_unitcell(len_a, len_b, len_c, alpha, beta, gamma):
|
|
37
149
|
"""
|
|
38
150
|
Calculate the three vectors spanning a box from the unit cell
|
|
@@ -160,6 +272,8 @@ def repeat_box(atoms, amount=1):
|
|
|
160
272
|
The repeated atoms.
|
|
161
273
|
Includes the original atoms (central box) in the beginning of
|
|
162
274
|
the atom array (stack).
|
|
275
|
+
If the input contains the ``sym_id`` annotation, the IDs are continued in the
|
|
276
|
+
repeated atoms, i.e. they do not start at 0 again.
|
|
163
277
|
indices : ndarray, dtype=int, shape=(n,3)
|
|
164
278
|
Indices to the atoms in the original atom array (stack).
|
|
165
279
|
Equal to
|
|
@@ -234,11 +348,20 @@ def repeat_box(atoms, amount=1):
|
|
|
234
348
|
>>> print(indices)
|
|
235
349
|
[0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
|
|
236
350
|
1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1]
|
|
351
|
+
|
|
352
|
+
The ``sym_id`` is continued in the repeated atoms.
|
|
353
|
+
|
|
354
|
+
>>> array.set_annotation("sym_id", np.array([0, 0]))
|
|
355
|
+
>>> repeated, indices = repeat_box(array)
|
|
356
|
+
>>> print(repeated.sym_id)
|
|
357
|
+
[ 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11
|
|
358
|
+
12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19 20 20 21 21 22 22 23 23
|
|
359
|
+
24 24 25 25 26 26]
|
|
237
360
|
"""
|
|
238
361
|
if atoms.box is None:
|
|
239
362
|
raise BadStructureError("Structure has no box")
|
|
240
363
|
|
|
241
|
-
repeat_coord, indices = repeat_box_coord(atoms.coord, atoms.box)
|
|
364
|
+
repeat_coord, indices = repeat_box_coord(atoms.coord, atoms.box, amount)
|
|
242
365
|
# Unroll repeated coordinates for input to 'repeat()'
|
|
243
366
|
if repeat_coord.ndim == 2:
|
|
244
367
|
repeat_coord = repeat_coord.reshape(-1, atoms.array_length(), 3)
|
|
@@ -247,7 +370,16 @@ def repeat_box(atoms, amount=1):
|
|
|
247
370
|
atoms.stack_depth(), -1, atoms.array_length(), 3
|
|
248
371
|
)
|
|
249
372
|
repeat_coord = np.swapaxes(repeat_coord, 0, 1)
|
|
250
|
-
|
|
373
|
+
|
|
374
|
+
repeated_atoms = repeat(atoms, repeat_coord)
|
|
375
|
+
if "sym_id" in atoms.get_annotation_categories():
|
|
376
|
+
max_sym_id = np.max(atoms.sym_id)
|
|
377
|
+
# for the first repeat, (max_sym_id + 1) is added,
|
|
378
|
+
# for the second repeat 2*(max_sym_id + 1) etc.
|
|
379
|
+
repeated_atoms.sym_id += (max_sym_id + 1) * (
|
|
380
|
+
np.arange(repeated_atoms.array_length()) // atoms.array_length()
|
|
381
|
+
)
|
|
382
|
+
return repeated_atoms, indices
|
|
251
383
|
|
|
252
384
|
|
|
253
385
|
def repeat_box_coord(coord, box, amount=1):
|
|
@@ -584,3 +716,9 @@ def is_orthogonal(box):
|
|
|
584
716
|
& (np.abs(vector_dot(box[..., 0, :], box[..., 2, :])) < tol)
|
|
585
717
|
& (np.abs(vector_dot(box[..., 1, :], box[..., 2, :])) < tol)
|
|
586
718
|
)
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
@functools.cache
|
|
722
|
+
def _get_transformation_data():
|
|
723
|
+
with open(Path(__file__).parent / "spacegroups.json") as file:
|
|
724
|
+
return json.load(file)
|
|
Binary file
|
biotite/structure/celllist.pyx
CHANGED
|
@@ -55,7 +55,6 @@ cdef class CellList:
|
|
|
55
55
|
periodic : bool, optional
|
|
56
56
|
If true, the cell list considers periodic copies of atoms.
|
|
57
57
|
The periodicity is based on the `box` attribute of `atom_array`.
|
|
58
|
-
(Default: False)
|
|
59
58
|
box : ndarray, dtype=float, shape=(3,3), optional
|
|
60
59
|
If provided, the periodicity is based on this parameter instead
|
|
61
60
|
of the :attr:`box` attribute of `atom_array`.
|