biotite 1.5.0__cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.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 +18 -0
- biotite/application/__init__.py +69 -0
- biotite/application/application.py +276 -0
- biotite/application/autodock/__init__.py +12 -0
- biotite/application/autodock/app.py +500 -0
- biotite/application/blast/__init__.py +14 -0
- biotite/application/blast/alignment.py +92 -0
- biotite/application/blast/webapp.py +428 -0
- biotite/application/clustalo/__init__.py +12 -0
- biotite/application/clustalo/app.py +223 -0
- biotite/application/dssp/__init__.py +12 -0
- biotite/application/dssp/app.py +216 -0
- biotite/application/localapp.py +342 -0
- biotite/application/mafft/__init__.py +12 -0
- biotite/application/mafft/app.py +116 -0
- biotite/application/msaapp.py +363 -0
- biotite/application/muscle/__init__.py +13 -0
- biotite/application/muscle/app3.py +227 -0
- biotite/application/muscle/app5.py +163 -0
- biotite/application/sra/__init__.py +18 -0
- biotite/application/sra/app.py +447 -0
- biotite/application/tantan/__init__.py +12 -0
- biotite/application/tantan/app.py +199 -0
- biotite/application/util.py +77 -0
- biotite/application/viennarna/__init__.py +18 -0
- biotite/application/viennarna/rnaalifold.py +310 -0
- biotite/application/viennarna/rnafold.py +254 -0
- biotite/application/viennarna/rnaplot.py +208 -0
- biotite/application/viennarna/util.py +77 -0
- biotite/application/webapp.py +76 -0
- biotite/copyable.py +71 -0
- biotite/database/__init__.py +23 -0
- biotite/database/afdb/__init__.py +12 -0
- biotite/database/afdb/download.py +197 -0
- biotite/database/entrez/__init__.py +15 -0
- biotite/database/entrez/check.py +60 -0
- biotite/database/entrez/dbnames.py +101 -0
- biotite/database/entrez/download.py +228 -0
- biotite/database/entrez/key.py +44 -0
- biotite/database/entrez/query.py +263 -0
- biotite/database/error.py +16 -0
- biotite/database/pubchem/__init__.py +21 -0
- biotite/database/pubchem/download.py +258 -0
- biotite/database/pubchem/error.py +30 -0
- biotite/database/pubchem/query.py +819 -0
- biotite/database/pubchem/throttle.py +98 -0
- biotite/database/rcsb/__init__.py +13 -0
- biotite/database/rcsb/download.py +161 -0
- biotite/database/rcsb/query.py +963 -0
- biotite/database/uniprot/__init__.py +13 -0
- biotite/database/uniprot/check.py +40 -0
- biotite/database/uniprot/download.py +126 -0
- biotite/database/uniprot/query.py +292 -0
- biotite/file.py +244 -0
- 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 +1228 -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/__init__.py +84 -0
- biotite/sequence/align/__init__.py +199 -0
- biotite/sequence/align/alignment.py +702 -0
- biotite/sequence/align/banded.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/banded.pyx +652 -0
- biotite/sequence/align/buckets.py +71 -0
- biotite/sequence/align/cigar.py +425 -0
- biotite/sequence/align/kmeralphabet.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/kmeralphabet.pyx +595 -0
- biotite/sequence/align/kmersimilarity.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/kmersimilarity.pyx +233 -0
- biotite/sequence/align/kmertable.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/kmertable.pyx +3411 -0
- biotite/sequence/align/localgapped.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/localgapped.pyx +892 -0
- biotite/sequence/align/localungapped.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/localungapped.pyx +279 -0
- biotite/sequence/align/matrix.py +631 -0
- biotite/sequence/align/matrix_data/3Di.mat +24 -0
- biotite/sequence/align/matrix_data/BLOSUM100.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM30.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM35.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM40.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM45.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM50.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM50_13p.mat +25 -0
- biotite/sequence/align/matrix_data/BLOSUM50_14.3.mat +25 -0
- biotite/sequence/align/matrix_data/BLOSUM50_5.0.mat +25 -0
- biotite/sequence/align/matrix_data/BLOSUM55.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM60.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM62.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM62_13p.mat +25 -0
- biotite/sequence/align/matrix_data/BLOSUM62_14.3.mat +25 -0
- biotite/sequence/align/matrix_data/BLOSUM62_5.0.mat +25 -0
- biotite/sequence/align/matrix_data/BLOSUM65.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM70.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM75.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM80.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM85.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUM90.mat +31 -0
- biotite/sequence/align/matrix_data/BLOSUMN.mat +31 -0
- biotite/sequence/align/matrix_data/CorBLOSUM49_5.0.mat +25 -0
- biotite/sequence/align/matrix_data/CorBLOSUM57_13p.mat +25 -0
- biotite/sequence/align/matrix_data/CorBLOSUM57_14.3.mat +25 -0
- biotite/sequence/align/matrix_data/CorBLOSUM61_5.0.mat +25 -0
- biotite/sequence/align/matrix_data/CorBLOSUM66_13p.mat +25 -0
- biotite/sequence/align/matrix_data/CorBLOSUM67_14.3.mat +25 -0
- biotite/sequence/align/matrix_data/DAYHOFF.mat +32 -0
- biotite/sequence/align/matrix_data/GONNET.mat +26 -0
- biotite/sequence/align/matrix_data/IDENTITY.mat +25 -0
- biotite/sequence/align/matrix_data/MATCH.mat +25 -0
- biotite/sequence/align/matrix_data/NUC.mat +25 -0
- biotite/sequence/align/matrix_data/PAM10.mat +34 -0
- biotite/sequence/align/matrix_data/PAM100.mat +34 -0
- biotite/sequence/align/matrix_data/PAM110.mat +34 -0
- biotite/sequence/align/matrix_data/PAM120.mat +34 -0
- biotite/sequence/align/matrix_data/PAM130.mat +34 -0
- biotite/sequence/align/matrix_data/PAM140.mat +34 -0
- biotite/sequence/align/matrix_data/PAM150.mat +34 -0
- biotite/sequence/align/matrix_data/PAM160.mat +34 -0
- biotite/sequence/align/matrix_data/PAM170.mat +34 -0
- biotite/sequence/align/matrix_data/PAM180.mat +34 -0
- biotite/sequence/align/matrix_data/PAM190.mat +34 -0
- biotite/sequence/align/matrix_data/PAM20.mat +34 -0
- biotite/sequence/align/matrix_data/PAM200.mat +34 -0
- biotite/sequence/align/matrix_data/PAM210.mat +34 -0
- biotite/sequence/align/matrix_data/PAM220.mat +34 -0
- biotite/sequence/align/matrix_data/PAM230.mat +34 -0
- biotite/sequence/align/matrix_data/PAM240.mat +34 -0
- biotite/sequence/align/matrix_data/PAM250.mat +34 -0
- biotite/sequence/align/matrix_data/PAM260.mat +34 -0
- biotite/sequence/align/matrix_data/PAM270.mat +34 -0
- biotite/sequence/align/matrix_data/PAM280.mat +34 -0
- biotite/sequence/align/matrix_data/PAM290.mat +34 -0
- biotite/sequence/align/matrix_data/PAM30.mat +34 -0
- biotite/sequence/align/matrix_data/PAM300.mat +34 -0
- biotite/sequence/align/matrix_data/PAM310.mat +34 -0
- biotite/sequence/align/matrix_data/PAM320.mat +34 -0
- biotite/sequence/align/matrix_data/PAM330.mat +34 -0
- biotite/sequence/align/matrix_data/PAM340.mat +34 -0
- biotite/sequence/align/matrix_data/PAM350.mat +34 -0
- biotite/sequence/align/matrix_data/PAM360.mat +34 -0
- biotite/sequence/align/matrix_data/PAM370.mat +34 -0
- biotite/sequence/align/matrix_data/PAM380.mat +34 -0
- biotite/sequence/align/matrix_data/PAM390.mat +34 -0
- biotite/sequence/align/matrix_data/PAM40.mat +34 -0
- biotite/sequence/align/matrix_data/PAM400.mat +34 -0
- biotite/sequence/align/matrix_data/PAM410.mat +34 -0
- biotite/sequence/align/matrix_data/PAM420.mat +34 -0
- biotite/sequence/align/matrix_data/PAM430.mat +34 -0
- biotite/sequence/align/matrix_data/PAM440.mat +34 -0
- biotite/sequence/align/matrix_data/PAM450.mat +34 -0
- biotite/sequence/align/matrix_data/PAM460.mat +34 -0
- biotite/sequence/align/matrix_data/PAM470.mat +34 -0
- biotite/sequence/align/matrix_data/PAM480.mat +34 -0
- biotite/sequence/align/matrix_data/PAM490.mat +34 -0
- biotite/sequence/align/matrix_data/PAM50.mat +34 -0
- biotite/sequence/align/matrix_data/PAM500.mat +34 -0
- biotite/sequence/align/matrix_data/PAM60.mat +34 -0
- biotite/sequence/align/matrix_data/PAM70.mat +34 -0
- biotite/sequence/align/matrix_data/PAM80.mat +34 -0
- biotite/sequence/align/matrix_data/PAM90.mat +34 -0
- biotite/sequence/align/matrix_data/PB.license +21 -0
- biotite/sequence/align/matrix_data/PB.mat +18 -0
- biotite/sequence/align/matrix_data/RBLOSUM52_5.0.mat +25 -0
- biotite/sequence/align/matrix_data/RBLOSUM59_13p.mat +25 -0
- biotite/sequence/align/matrix_data/RBLOSUM59_14.3.mat +25 -0
- biotite/sequence/align/matrix_data/RBLOSUM64_5.0.mat +25 -0
- biotite/sequence/align/matrix_data/RBLOSUM69_13p.mat +25 -0
- biotite/sequence/align/matrix_data/RBLOSUM69_14.3.mat +25 -0
- biotite/sequence/align/multiple.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/multiple.pyx +619 -0
- biotite/sequence/align/pairwise.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/pairwise.pyx +585 -0
- biotite/sequence/align/permutation.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/permutation.pyx +313 -0
- biotite/sequence/align/primes.txt +821 -0
- biotite/sequence/align/selector.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/selector.pyx +954 -0
- biotite/sequence/align/statistics.py +264 -0
- biotite/sequence/align/tracetable.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/align/tracetable.pxd +64 -0
- biotite/sequence/align/tracetable.pyx +370 -0
- biotite/sequence/alphabet.py +555 -0
- biotite/sequence/annotation.py +836 -0
- biotite/sequence/codec.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/codec.pyx +155 -0
- biotite/sequence/codon.py +476 -0
- biotite/sequence/codon_tables.txt +202 -0
- biotite/sequence/graphics/__init__.py +33 -0
- biotite/sequence/graphics/alignment.py +1101 -0
- biotite/sequence/graphics/color_schemes/3di_flower.json +48 -0
- biotite/sequence/graphics/color_schemes/autumn.json +51 -0
- biotite/sequence/graphics/color_schemes/blossom.json +51 -0
- biotite/sequence/graphics/color_schemes/clustalx_dna.json +11 -0
- biotite/sequence/graphics/color_schemes/clustalx_protein.json +28 -0
- biotite/sequence/graphics/color_schemes/flower.json +51 -0
- biotite/sequence/graphics/color_schemes/jalview_buried.json +31 -0
- biotite/sequence/graphics/color_schemes/jalview_hydrophobicity.json +31 -0
- biotite/sequence/graphics/color_schemes/jalview_prop_helix.json +31 -0
- biotite/sequence/graphics/color_schemes/jalview_prop_strand.json +31 -0
- biotite/sequence/graphics/color_schemes/jalview_prop_turn.json +31 -0
- biotite/sequence/graphics/color_schemes/jalview_taylor.json +28 -0
- biotite/sequence/graphics/color_schemes/jalview_zappo.json +28 -0
- biotite/sequence/graphics/color_schemes/ocean.json +51 -0
- biotite/sequence/graphics/color_schemes/pb_flower.json +40 -0
- biotite/sequence/graphics/color_schemes/rainbow_dna.json +11 -0
- biotite/sequence/graphics/color_schemes/rainbow_protein.json +30 -0
- biotite/sequence/graphics/color_schemes/spring.json +51 -0
- biotite/sequence/graphics/color_schemes/sunset.json +51 -0
- biotite/sequence/graphics/color_schemes/wither.json +51 -0
- biotite/sequence/graphics/colorschemes.py +170 -0
- biotite/sequence/graphics/dendrogram.py +231 -0
- biotite/sequence/graphics/features.py +544 -0
- biotite/sequence/graphics/logo.py +102 -0
- biotite/sequence/graphics/plasmid.py +712 -0
- biotite/sequence/io/__init__.py +12 -0
- biotite/sequence/io/fasta/__init__.py +22 -0
- biotite/sequence/io/fasta/convert.py +283 -0
- biotite/sequence/io/fasta/file.py +265 -0
- biotite/sequence/io/fastq/__init__.py +19 -0
- biotite/sequence/io/fastq/convert.py +117 -0
- biotite/sequence/io/fastq/file.py +507 -0
- biotite/sequence/io/genbank/__init__.py +17 -0
- biotite/sequence/io/genbank/annotation.py +269 -0
- biotite/sequence/io/genbank/file.py +573 -0
- biotite/sequence/io/genbank/metadata.py +336 -0
- biotite/sequence/io/genbank/sequence.py +173 -0
- biotite/sequence/io/general.py +201 -0
- biotite/sequence/io/gff/__init__.py +26 -0
- biotite/sequence/io/gff/convert.py +128 -0
- biotite/sequence/io/gff/file.py +449 -0
- biotite/sequence/phylo/__init__.py +36 -0
- biotite/sequence/phylo/nj.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/phylo/nj.pyx +221 -0
- biotite/sequence/phylo/tree.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/phylo/tree.pyx +1169 -0
- biotite/sequence/phylo/upgma.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/sequence/phylo/upgma.pyx +164 -0
- biotite/sequence/profile.py +561 -0
- biotite/sequence/search.py +117 -0
- biotite/sequence/seqtypes.py +720 -0
- biotite/sequence/sequence.py +373 -0
- biotite/setup_ccd.py +197 -0
- biotite/structure/__init__.py +135 -0
- biotite/structure/alphabet/__init__.py +25 -0
- biotite/structure/alphabet/encoder.py +332 -0
- biotite/structure/alphabet/encoder_weights_3di.kerasify +0 -0
- biotite/structure/alphabet/i3d.py +109 -0
- biotite/structure/alphabet/layers.py +86 -0
- biotite/structure/alphabet/pb.license +21 -0
- biotite/structure/alphabet/pb.py +170 -0
- biotite/structure/alphabet/unkerasify.py +128 -0
- biotite/structure/atoms.py +1562 -0
- biotite/structure/basepairs.py +1403 -0
- biotite/structure/bonds.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/structure/bonds.pyx +2036 -0
- biotite/structure/box.py +724 -0
- biotite/structure/celllist.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/structure/celllist.pyx +864 -0
- biotite/structure/chains.py +310 -0
- biotite/structure/charges.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/structure/charges.pyx +520 -0
- biotite/structure/compare.py +683 -0
- biotite/structure/density.py +109 -0
- biotite/structure/dotbracket.py +213 -0
- biotite/structure/error.py +39 -0
- biotite/structure/filter.py +591 -0
- biotite/structure/geometry.py +817 -0
- biotite/structure/graphics/__init__.py +13 -0
- biotite/structure/graphics/atoms.py +243 -0
- biotite/structure/graphics/rna.py +298 -0
- biotite/structure/hbond.py +425 -0
- biotite/structure/info/__init__.py +24 -0
- biotite/structure/info/atom_masses.json +121 -0
- biotite/structure/info/atoms.py +98 -0
- biotite/structure/info/bonds.py +149 -0
- biotite/structure/info/ccd.py +200 -0
- biotite/structure/info/components.bcif +0 -0
- biotite/structure/info/groups.py +128 -0
- biotite/structure/info/masses.py +121 -0
- biotite/structure/info/misc.py +137 -0
- biotite/structure/info/radii.py +267 -0
- biotite/structure/info/standardize.py +185 -0
- biotite/structure/integrity.py +213 -0
- biotite/structure/io/__init__.py +29 -0
- biotite/structure/io/dcd/__init__.py +13 -0
- biotite/structure/io/dcd/file.py +67 -0
- biotite/structure/io/general.py +243 -0
- biotite/structure/io/gro/__init__.py +14 -0
- biotite/structure/io/gro/file.py +343 -0
- biotite/structure/io/mol/__init__.py +20 -0
- biotite/structure/io/mol/convert.py +112 -0
- biotite/structure/io/mol/ctab.py +420 -0
- biotite/structure/io/mol/header.py +120 -0
- biotite/structure/io/mol/mol.py +149 -0
- biotite/structure/io/mol/sdf.py +940 -0
- biotite/structure/io/netcdf/__init__.py +13 -0
- biotite/structure/io/netcdf/file.py +64 -0
- biotite/structure/io/pdb/__init__.py +20 -0
- biotite/structure/io/pdb/convert.py +389 -0
- biotite/structure/io/pdb/file.py +1380 -0
- biotite/structure/io/pdb/hybrid36.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/structure/io/pdb/hybrid36.pyx +242 -0
- biotite/structure/io/pdbqt/__init__.py +15 -0
- biotite/structure/io/pdbqt/convert.py +113 -0
- biotite/structure/io/pdbqt/file.py +688 -0
- biotite/structure/io/pdbx/__init__.py +23 -0
- biotite/structure/io/pdbx/bcif.py +674 -0
- biotite/structure/io/pdbx/cif.py +1091 -0
- biotite/structure/io/pdbx/component.py +251 -0
- biotite/structure/io/pdbx/compress.py +362 -0
- biotite/structure/io/pdbx/convert.py +2113 -0
- biotite/structure/io/pdbx/encoding.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/structure/io/pdbx/encoding.pyx +1078 -0
- biotite/structure/io/trajfile.py +696 -0
- biotite/structure/io/trr/__init__.py +13 -0
- biotite/structure/io/trr/file.py +43 -0
- biotite/structure/io/util.py +38 -0
- biotite/structure/io/xtc/__init__.py +13 -0
- biotite/structure/io/xtc/file.py +43 -0
- biotite/structure/mechanics.py +72 -0
- biotite/structure/molecules.py +337 -0
- biotite/structure/pseudoknots.py +622 -0
- biotite/structure/rdf.py +245 -0
- biotite/structure/repair.py +302 -0
- biotite/structure/residues.py +716 -0
- biotite/structure/rings.py +451 -0
- biotite/structure/sasa.cpython-313-x86_64-linux-gnu.so +0 -0
- biotite/structure/sasa.pyx +322 -0
- biotite/structure/segments.py +328 -0
- biotite/structure/sequence.py +110 -0
- biotite/structure/spacegroups.json +1567 -0
- biotite/structure/spacegroups.license +26 -0
- biotite/structure/sse.py +306 -0
- biotite/structure/superimpose.py +511 -0
- biotite/structure/tm.py +581 -0
- biotite/structure/transform.py +736 -0
- biotite/structure/util.py +160 -0
- biotite/version.py +34 -0
- biotite/visualize.py +375 -0
- biotite-1.5.0.dist-info/METADATA +162 -0
- biotite-1.5.0.dist-info/RECORD +354 -0
- biotite-1.5.0.dist-info/WHEEL +6 -0
- biotite-1.5.0.dist-info/licenses/LICENSE.rst +30 -0
biotite/structure/box.py
ADDED
|
@@ -0,0 +1,724 @@
|
|
|
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
|
+
Functions related to working with the simulation box or unit cell
|
|
7
|
+
of a structure.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
__name__ = "biotite.structure"
|
|
11
|
+
__author__ = "Patrick Kunzmann"
|
|
12
|
+
__all__ = [
|
|
13
|
+
"space_group_transforms",
|
|
14
|
+
"vectors_from_unitcell",
|
|
15
|
+
"unitcell_from_vectors",
|
|
16
|
+
"box_volume",
|
|
17
|
+
"repeat_box",
|
|
18
|
+
"repeat_box_coord",
|
|
19
|
+
"move_inside_box",
|
|
20
|
+
"remove_pbc",
|
|
21
|
+
"remove_pbc_from_coord",
|
|
22
|
+
"coord_to_fraction",
|
|
23
|
+
"fraction_to_coord",
|
|
24
|
+
"is_orthogonal",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
import functools
|
|
28
|
+
import json
|
|
29
|
+
from numbers import Integral
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
import numpy as np
|
|
32
|
+
import numpy.linalg as linalg
|
|
33
|
+
from biotite.structure.atoms import repeat
|
|
34
|
+
from biotite.structure.chains import get_chain_masks, get_chain_starts
|
|
35
|
+
from biotite.structure.error import BadStructureError
|
|
36
|
+
from biotite.structure.molecules import get_molecule_masks
|
|
37
|
+
from biotite.structure.transform import AffineTransformation
|
|
38
|
+
from biotite.structure.util import vector_dot
|
|
39
|
+
|
|
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
|
+
|
|
148
|
+
def vectors_from_unitcell(len_a, len_b, len_c, alpha, beta, gamma):
|
|
149
|
+
"""
|
|
150
|
+
Calculate the three vectors spanning a box from the unit cell
|
|
151
|
+
lengths and angles.
|
|
152
|
+
|
|
153
|
+
The return value of this function are the three box vectors as
|
|
154
|
+
required for the :attr:`box` attribute in atom arrays and stacks.
|
|
155
|
+
|
|
156
|
+
Parameters
|
|
157
|
+
----------
|
|
158
|
+
len_a, len_b, len_c : float
|
|
159
|
+
The lengths of the three box/unit cell vectors *a*, *b* and *c*.
|
|
160
|
+
alpha, beta, gamma : float
|
|
161
|
+
The angles between the box vectors in radians.
|
|
162
|
+
*alpha* is the angle between *b* and *c*,
|
|
163
|
+
*beta* between *a* and *c*, *gamma* between *a* and *b*.
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
box : ndarray, dtype=float, shape=(3,3)
|
|
168
|
+
The three box vectors.
|
|
169
|
+
The vector components are in the last dimension.
|
|
170
|
+
The value can be directly used as :attr:`box` attribute in an
|
|
171
|
+
atom array.
|
|
172
|
+
|
|
173
|
+
See Also
|
|
174
|
+
--------
|
|
175
|
+
unitcell_from_vectors : The reverse operation.
|
|
176
|
+
"""
|
|
177
|
+
a_x = len_a
|
|
178
|
+
b_x = len_b * np.cos(gamma)
|
|
179
|
+
b_y = len_b * np.sin(gamma)
|
|
180
|
+
c_x = len_c * np.cos(beta)
|
|
181
|
+
c_y = len_c * (np.cos(alpha) - np.cos(beta) * np.cos(gamma)) / np.sin(gamma)
|
|
182
|
+
c_z = np.sqrt(len_c * len_c - c_x * c_x - c_y * c_y)
|
|
183
|
+
box = np.array([[a_x, 0, 0], [b_x, b_y, 0], [c_x, c_y, c_z]], dtype=np.float32)
|
|
184
|
+
|
|
185
|
+
# Fix numerical errors, as values, that are actually 0,
|
|
186
|
+
# might not be calculated as such
|
|
187
|
+
tol = 1e-4 * (len_a + len_b + len_c)
|
|
188
|
+
box[np.abs(box) < tol] = 0
|
|
189
|
+
|
|
190
|
+
return box
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def unitcell_from_vectors(box):
|
|
194
|
+
"""
|
|
195
|
+
Get the unit cell lengths and angles from box vectors.
|
|
196
|
+
|
|
197
|
+
This is the reverse operation of :func:`vectors_from_unitcell()`.
|
|
198
|
+
|
|
199
|
+
Parameters
|
|
200
|
+
----------
|
|
201
|
+
box : ndarray, shape=(3,3)
|
|
202
|
+
The box vectors.
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
len_a, len_b, len_c : float
|
|
207
|
+
The lengths of the three box/unit cell vectors *a*, *b* and *c*.
|
|
208
|
+
alpha, beta, gamma : float
|
|
209
|
+
The angles between the box vectors in radians.
|
|
210
|
+
|
|
211
|
+
See Also
|
|
212
|
+
--------
|
|
213
|
+
vectors_from_unitcell : The reverse operation.
|
|
214
|
+
"""
|
|
215
|
+
a = box[0]
|
|
216
|
+
b = box[1]
|
|
217
|
+
c = box[2]
|
|
218
|
+
len_a = linalg.norm(a)
|
|
219
|
+
len_b = linalg.norm(b)
|
|
220
|
+
len_c = linalg.norm(c)
|
|
221
|
+
alpha = np.arccos(np.dot(b, c) / (len_b * len_c))
|
|
222
|
+
beta = np.arccos(np.dot(a, c) / (len_a * len_c))
|
|
223
|
+
gamma = np.arccos(np.dot(a, b) / (len_a * len_b))
|
|
224
|
+
return len_a, len_b, len_c, alpha, beta, gamma
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def box_volume(box):
|
|
228
|
+
"""
|
|
229
|
+
Get the volume of one ore multiple boxes.
|
|
230
|
+
|
|
231
|
+
Parameters
|
|
232
|
+
----------
|
|
233
|
+
box : ndarray, shape=(3,3) or shape=(m,3,3)
|
|
234
|
+
One or multiple boxes to get the volume for.
|
|
235
|
+
|
|
236
|
+
Returns
|
|
237
|
+
-------
|
|
238
|
+
volume : float or ndarray, shape=(m,)
|
|
239
|
+
The volume(s) of the given box(es).
|
|
240
|
+
"""
|
|
241
|
+
# Using the triple product
|
|
242
|
+
return np.abs(linalg.det(box))
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def repeat_box(atoms, amount=1):
|
|
246
|
+
r"""
|
|
247
|
+
Repeat the atoms in a box by duplicating and placing them in
|
|
248
|
+
adjacent boxes.
|
|
249
|
+
|
|
250
|
+
The output atom array (stack) contains the original atoms (central
|
|
251
|
+
box) and duplicates of them in the given amount of adjacent boxes.
|
|
252
|
+
The coordinates of the duplicate atoms are translated accordingly
|
|
253
|
+
by the box coordinates.
|
|
254
|
+
|
|
255
|
+
Parameters
|
|
256
|
+
----------
|
|
257
|
+
atoms : AtomArray or AtomArrayStack
|
|
258
|
+
The atoms to be repeated.
|
|
259
|
+
If `atoms` is a :class:`AtomArrayStack`, the atoms are repeated
|
|
260
|
+
for each model, according to the box of each model.
|
|
261
|
+
amount : int, optional
|
|
262
|
+
The amount of boxes that are created in each direction of the
|
|
263
|
+
central box.
|
|
264
|
+
Hence, the total amount of boxes is
|
|
265
|
+
:math:`(1 + 2 \cdot \text{amount}) ^ 3`.
|
|
266
|
+
By default, one box is created in each direction, totalling in
|
|
267
|
+
27 boxes.
|
|
268
|
+
|
|
269
|
+
Returns
|
|
270
|
+
-------
|
|
271
|
+
repeated : AtomArray or AtomArrayStack
|
|
272
|
+
The repeated atoms.
|
|
273
|
+
Includes the original atoms (central box) in the beginning of
|
|
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.
|
|
277
|
+
indices : ndarray, dtype=int, shape=(n,3)
|
|
278
|
+
Indices to the atoms in the original atom array (stack).
|
|
279
|
+
Equal to
|
|
280
|
+
``numpy.tile(np.arange(atoms.array_length()), (1 + 2 * amount) ** 3)``.
|
|
281
|
+
|
|
282
|
+
See Also
|
|
283
|
+
--------
|
|
284
|
+
repeat_box_coord : Variant that acts directly on coordinates.
|
|
285
|
+
|
|
286
|
+
Examples
|
|
287
|
+
--------
|
|
288
|
+
|
|
289
|
+
>>> array = AtomArray(length=2)
|
|
290
|
+
>>> array.coord = np.array([[1,5,3], [-1,2,5]], dtype=float)
|
|
291
|
+
>>> array.box = np.array([[10,0,0], [0,10,0], [0,0,10]], dtype=float)
|
|
292
|
+
>>> repeated, indices = repeat_box(array)
|
|
293
|
+
>>> print(repeated.coord)
|
|
294
|
+
[[ 1. 5. 3.]
|
|
295
|
+
[ -1. 2. 5.]
|
|
296
|
+
[ -9. -5. -7.]
|
|
297
|
+
[-11. -8. -5.]
|
|
298
|
+
[ -9. -5. 3.]
|
|
299
|
+
[-11. -8. 5.]
|
|
300
|
+
[ -9. -5. 13.]
|
|
301
|
+
[-11. -8. 15.]
|
|
302
|
+
[ -9. 5. -7.]
|
|
303
|
+
[-11. 2. -5.]
|
|
304
|
+
[ -9. 5. 3.]
|
|
305
|
+
[-11. 2. 5.]
|
|
306
|
+
[ -9. 5. 13.]
|
|
307
|
+
[-11. 2. 15.]
|
|
308
|
+
[ -9. 15. -7.]
|
|
309
|
+
[-11. 12. -5.]
|
|
310
|
+
[ -9. 15. 3.]
|
|
311
|
+
[-11. 12. 5.]
|
|
312
|
+
[ -9. 15. 13.]
|
|
313
|
+
[-11. 12. 15.]
|
|
314
|
+
[ 1. -5. -7.]
|
|
315
|
+
[ -1. -8. -5.]
|
|
316
|
+
[ 1. -5. 3.]
|
|
317
|
+
[ -1. -8. 5.]
|
|
318
|
+
[ 1. -5. 13.]
|
|
319
|
+
[ -1. -8. 15.]
|
|
320
|
+
[ 1. 5. -7.]
|
|
321
|
+
[ -1. 2. -5.]
|
|
322
|
+
[ 1. 5. 13.]
|
|
323
|
+
[ -1. 2. 15.]
|
|
324
|
+
[ 1. 15. -7.]
|
|
325
|
+
[ -1. 12. -5.]
|
|
326
|
+
[ 1. 15. 3.]
|
|
327
|
+
[ -1. 12. 5.]
|
|
328
|
+
[ 1. 15. 13.]
|
|
329
|
+
[ -1. 12. 15.]
|
|
330
|
+
[ 11. -5. -7.]
|
|
331
|
+
[ 9. -8. -5.]
|
|
332
|
+
[ 11. -5. 3.]
|
|
333
|
+
[ 9. -8. 5.]
|
|
334
|
+
[ 11. -5. 13.]
|
|
335
|
+
[ 9. -8. 15.]
|
|
336
|
+
[ 11. 5. -7.]
|
|
337
|
+
[ 9. 2. -5.]
|
|
338
|
+
[ 11. 5. 3.]
|
|
339
|
+
[ 9. 2. 5.]
|
|
340
|
+
[ 11. 5. 13.]
|
|
341
|
+
[ 9. 2. 15.]
|
|
342
|
+
[ 11. 15. -7.]
|
|
343
|
+
[ 9. 12. -5.]
|
|
344
|
+
[ 11. 15. 3.]
|
|
345
|
+
[ 9. 12. 5.]
|
|
346
|
+
[ 11. 15. 13.]
|
|
347
|
+
[ 9. 12. 15.]]
|
|
348
|
+
>>> print(indices)
|
|
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
|
|
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]
|
|
360
|
+
"""
|
|
361
|
+
if atoms.box is None:
|
|
362
|
+
raise BadStructureError("Structure has no box")
|
|
363
|
+
|
|
364
|
+
repeat_coord, indices = repeat_box_coord(atoms.coord, atoms.box, amount)
|
|
365
|
+
# Unroll repeated coordinates for input to 'repeat()'
|
|
366
|
+
if repeat_coord.ndim == 2:
|
|
367
|
+
repeat_coord = repeat_coord.reshape(-1, atoms.array_length(), 3)
|
|
368
|
+
else: # ndim == 3
|
|
369
|
+
repeat_coord = repeat_coord.reshape(
|
|
370
|
+
atoms.stack_depth(), -1, atoms.array_length(), 3
|
|
371
|
+
)
|
|
372
|
+
repeat_coord = np.swapaxes(repeat_coord, 0, 1)
|
|
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
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def repeat_box_coord(coord, box, amount=1):
|
|
386
|
+
r"""
|
|
387
|
+
Similar to :func:`repeat_box()`, repeat the coordinates in a box by
|
|
388
|
+
duplicating and placing them in adjacent boxes.
|
|
389
|
+
|
|
390
|
+
Parameters
|
|
391
|
+
----------
|
|
392
|
+
coord : ndarray, dtype=float, shape=(n,3) or shape=(m,n,3)
|
|
393
|
+
The coordinates to be repeated.
|
|
394
|
+
box : ndarray, dtype=float, shape=(3,3) or shape=(m,3,3)
|
|
395
|
+
The reference box.
|
|
396
|
+
If only one box is provided, i.e. the shape is *(3,3)*,
|
|
397
|
+
the box is used for all models *m*, if the coordinates shape
|
|
398
|
+
is *(m,n,3)*.
|
|
399
|
+
amount : int, optional
|
|
400
|
+
The amount of boxes that are created in each direction of the
|
|
401
|
+
central box.
|
|
402
|
+
Hence, the total amount of boxes is
|
|
403
|
+
:math:`(1 + 2 \cdot \text{amount}) ^ 3`.
|
|
404
|
+
By default, one box is created in each direction, totalling in
|
|
405
|
+
27 boxes.
|
|
406
|
+
|
|
407
|
+
Returns
|
|
408
|
+
-------
|
|
409
|
+
repeated : ndarray, dtype=float, shape=(p,3) or shape=(m,p,3)
|
|
410
|
+
The repeated coordinates, with the same dimension as the input
|
|
411
|
+
`coord`.
|
|
412
|
+
Includes the original coordinates (central box) in the beginning
|
|
413
|
+
of the array.
|
|
414
|
+
indices : ndarray, dtype=int, shape=(p,3)
|
|
415
|
+
Indices to the coordinates in the original array.
|
|
416
|
+
Equal to
|
|
417
|
+
``numpy.tile(np.arange(coord.shape[-2]), (1 + 2 * amount) ** 3)``.
|
|
418
|
+
"""
|
|
419
|
+
if not isinstance(amount, Integral):
|
|
420
|
+
raise TypeError("The amount must be an integer")
|
|
421
|
+
# List of numpy arrays for each box repeat
|
|
422
|
+
coords_for_boxes = [coord]
|
|
423
|
+
for i in range(-amount, amount + 1):
|
|
424
|
+
for j in range(-amount, amount + 1):
|
|
425
|
+
for k in range(-amount, amount + 1):
|
|
426
|
+
# Omit the central box
|
|
427
|
+
if i != 0 or j != 0 or k != 0:
|
|
428
|
+
temp_coord = coord.copy()
|
|
429
|
+
# Shift coordinates to adjacent box/unit cell
|
|
430
|
+
translation_vec = np.sum(
|
|
431
|
+
box * np.array([i, j, k])[:, np.newaxis], axis=-2
|
|
432
|
+
)
|
|
433
|
+
# 'newaxis' to perform same translation on all
|
|
434
|
+
# atoms for each model
|
|
435
|
+
temp_coord += translation_vec[..., np.newaxis, :]
|
|
436
|
+
coords_for_boxes.append(temp_coord)
|
|
437
|
+
return (
|
|
438
|
+
np.concatenate(coords_for_boxes, axis=-2),
|
|
439
|
+
np.tile(np.arange(coord.shape[-2]), (1 + 2 * amount) ** 3),
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def move_inside_box(coord, box):
|
|
444
|
+
r"""
|
|
445
|
+
Move all coordinates into the given box, with the box vectors
|
|
446
|
+
originating at *(0,0,0)*.
|
|
447
|
+
|
|
448
|
+
Coordinates are outside the box, when they cannot be represented by
|
|
449
|
+
a linear combination of the box vectors with scalar factors
|
|
450
|
+
:math:`0 \le a_i \le 1`.
|
|
451
|
+
In this case the affected coordinates are translated by the box
|
|
452
|
+
vectors, so that they are inside the box.
|
|
453
|
+
|
|
454
|
+
Parameters
|
|
455
|
+
----------
|
|
456
|
+
coord : ndarray, dtype=float, shape=(n,3) or shape=(m,n,3)
|
|
457
|
+
The coordinates for one or multiple models.
|
|
458
|
+
box : ndarray, dtype=float, shape=(3,3) or shape=(m,3,3)
|
|
459
|
+
The box(es) for one or multiple models.
|
|
460
|
+
When `coord` is given for multiple models, :attr:`box` must be
|
|
461
|
+
given for multiple models as well.
|
|
462
|
+
|
|
463
|
+
Returns
|
|
464
|
+
-------
|
|
465
|
+
moved_coord : ndarray, dtype=float, shape=(n,3) or shape=(m,n,3)
|
|
466
|
+
The moved coordinates.
|
|
467
|
+
Has the same shape is the input `coord`.
|
|
468
|
+
|
|
469
|
+
Examples
|
|
470
|
+
--------
|
|
471
|
+
|
|
472
|
+
>>> box = np.array([[10,0,0], [0,10,0], [0,0,10]], dtype=float)
|
|
473
|
+
>>> inside_coord = [ 1, 2, 3]
|
|
474
|
+
>>> outside_coord = [ 1, 22, 54]
|
|
475
|
+
>>> other_outside_coord = [-4, 8, 6]
|
|
476
|
+
>>> coord = np.stack([inside_coord, outside_coord, other_outside_coord])
|
|
477
|
+
>>> print(coord)
|
|
478
|
+
[[ 1 2 3]
|
|
479
|
+
[ 1 22 54]
|
|
480
|
+
[-4 8 6]]
|
|
481
|
+
>>> moved_coord = move_inside_box(coord, box)
|
|
482
|
+
>>> print(moved_coord.astype(int))
|
|
483
|
+
[[1 2 3]
|
|
484
|
+
[1 2 4]
|
|
485
|
+
[6 8 6]]
|
|
486
|
+
"""
|
|
487
|
+
fractions = coord_to_fraction(coord, box)
|
|
488
|
+
fractions_rem = fractions % 1
|
|
489
|
+
return fraction_to_coord(fractions_rem, box)
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
def remove_pbc(atoms, selection=None):
|
|
493
|
+
"""
|
|
494
|
+
Remove segmentation caused by periodic boundary conditions from each
|
|
495
|
+
molecule in the given structure.
|
|
496
|
+
|
|
497
|
+
In this process the centroid of each molecule is moved into the
|
|
498
|
+
dimensions of the box.
|
|
499
|
+
To determine the molecules the structure is required to have an
|
|
500
|
+
associated `BondList`.
|
|
501
|
+
Otherwise segmentation removal is performed on a per-chain basis.
|
|
502
|
+
|
|
503
|
+
Parameters
|
|
504
|
+
----------
|
|
505
|
+
atoms : AtomArray, shape=(n,) or AtomArrayStack, shape=(m,n)
|
|
506
|
+
The potentially segmented structure.
|
|
507
|
+
The :attr:`box` attribute must be set in the structure.
|
|
508
|
+
An associated :attr:`bonds` attribute is recommended.
|
|
509
|
+
selection : ndarray, dtype=bool, shape=(n,)
|
|
510
|
+
Specifies which parts of `atoms` are sanitized, i.e the
|
|
511
|
+
segmentation is removed.
|
|
512
|
+
|
|
513
|
+
Returns
|
|
514
|
+
-------
|
|
515
|
+
sanitized_atoms : AtomArray or AtomArrayStack
|
|
516
|
+
The input structure with removed segmentation over periodic
|
|
517
|
+
boundaries.
|
|
518
|
+
|
|
519
|
+
See Also
|
|
520
|
+
--------
|
|
521
|
+
remove_pbc_from_coord : Variant that acts directly on coordinates.
|
|
522
|
+
|
|
523
|
+
Notes
|
|
524
|
+
-----
|
|
525
|
+
This function ensures that adjacent atoms in the input
|
|
526
|
+
:class:`AtomArray`/:class:`AtomArrayStack` are spatially close to
|
|
527
|
+
each other, i.e. their distance to each other is be smaller than the
|
|
528
|
+
half box size.
|
|
529
|
+
"""
|
|
530
|
+
# Avoid circular import
|
|
531
|
+
from biotite.structure.geometry import centroid
|
|
532
|
+
|
|
533
|
+
if atoms.box is None:
|
|
534
|
+
raise BadStructureError("The 'box' attribute must be set in the structure")
|
|
535
|
+
new_atoms = atoms.copy()
|
|
536
|
+
|
|
537
|
+
if atoms.bonds is not None:
|
|
538
|
+
molecule_masks = get_molecule_masks(atoms)
|
|
539
|
+
else:
|
|
540
|
+
molecule_masks = get_chain_masks(atoms, get_chain_starts(atoms))
|
|
541
|
+
|
|
542
|
+
for mask in molecule_masks:
|
|
543
|
+
if selection is not None:
|
|
544
|
+
mask &= selection
|
|
545
|
+
# Remove segmentation in molecule
|
|
546
|
+
new_atoms.coord[..., mask, :] = remove_pbc_from_coord(
|
|
547
|
+
new_atoms.coord[..., mask, :], atoms.box
|
|
548
|
+
)
|
|
549
|
+
# Put center of molecule into box
|
|
550
|
+
center = centroid(new_atoms.coord[..., mask, :])[..., np.newaxis, :]
|
|
551
|
+
center_in_box = move_inside_box(center, new_atoms.box)
|
|
552
|
+
new_atoms.coord[..., mask, :] += center_in_box - center
|
|
553
|
+
|
|
554
|
+
return new_atoms
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
def remove_pbc_from_coord(coord, box):
|
|
558
|
+
"""
|
|
559
|
+
Remove segmentation caused by periodic boundary conditions from
|
|
560
|
+
given coordinates.
|
|
561
|
+
|
|
562
|
+
In this process the first coordinate is taken as origin and
|
|
563
|
+
is moved inside the box.
|
|
564
|
+
All other coordinates are assembled relative to the origin by using
|
|
565
|
+
the displacement coordinates in adjacent array positions.
|
|
566
|
+
|
|
567
|
+
Parameters
|
|
568
|
+
----------
|
|
569
|
+
coord : ndarray, dtype=float, shape=(m,n,3) or shape=(n,3)
|
|
570
|
+
The coordinates of the potentially segmented structure.
|
|
571
|
+
box : ndarray, dtype=float, shape=(m,3,3) or shape=(3,3)
|
|
572
|
+
The simulation box or unit cell that is used as periodic
|
|
573
|
+
boundary.
|
|
574
|
+
The amount of dimensions must fit the `coord` parameter.
|
|
575
|
+
|
|
576
|
+
Returns
|
|
577
|
+
-------
|
|
578
|
+
sanitized_coord : ndarray, dtype=float, shape=(m,n,3) or shape=(n,3)
|
|
579
|
+
The reassembled coordinates.
|
|
580
|
+
|
|
581
|
+
See Also
|
|
582
|
+
--------
|
|
583
|
+
move_inside_box : The reverse operation.
|
|
584
|
+
|
|
585
|
+
Notes
|
|
586
|
+
-----
|
|
587
|
+
This function solves a common problem from MD simulation output:
|
|
588
|
+
When atoms move over the periodic boundary, they reappear on the
|
|
589
|
+
other side of the box, segmenting the structure.
|
|
590
|
+
This function reassembles the given coordinates, removing the
|
|
591
|
+
segmentation.
|
|
592
|
+
"""
|
|
593
|
+
|
|
594
|
+
# Import in function to avoid circular import
|
|
595
|
+
from biotite.structure.geometry import index_displacement
|
|
596
|
+
|
|
597
|
+
# Get the PBC-sanitized displacements of all coordinates
|
|
598
|
+
# to the respective next coordinate
|
|
599
|
+
index_pairs = np.stack(
|
|
600
|
+
[np.arange(0, coord.shape[-2] - 1), np.arange(1, coord.shape[-2])], axis=1
|
|
601
|
+
)
|
|
602
|
+
neighbour_disp = index_displacement(coord, index_pairs, box=box, periodic=True)
|
|
603
|
+
# Get the PBC-sanitized displacements of all but the first
|
|
604
|
+
# coordinates to (0,0,0)
|
|
605
|
+
absolute_disp = np.cumsum(neighbour_disp, axis=-2)
|
|
606
|
+
# The first coordinate should be inside the box
|
|
607
|
+
base_coord = move_inside_box(coord[..., 0:1, :], box)
|
|
608
|
+
# The new coordinates are obtained by adding the displacements
|
|
609
|
+
# to the new origin
|
|
610
|
+
sanitized_coord = np.zeros(coord.shape, coord.dtype)
|
|
611
|
+
sanitized_coord[..., 0:1, :] = base_coord
|
|
612
|
+
sanitized_coord[..., 1:, :] = base_coord + absolute_disp
|
|
613
|
+
return sanitized_coord
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
def coord_to_fraction(coord, box):
|
|
617
|
+
"""
|
|
618
|
+
Transform coordinates to fractions of box vectors.
|
|
619
|
+
|
|
620
|
+
Parameters
|
|
621
|
+
----------
|
|
622
|
+
coord : ndarray, dtype=float, shape=(n,3) or shape=(m,n,3)
|
|
623
|
+
The coordinates for one or multiple models.
|
|
624
|
+
box : ndarray, dtype=float, shape=(3,3) or shape=(m,3,3)
|
|
625
|
+
The box(es) for one or multiple models.
|
|
626
|
+
When `coord` is given for multiple models, :attr:`box` must be
|
|
627
|
+
given for multiple models as well.
|
|
628
|
+
|
|
629
|
+
Returns
|
|
630
|
+
-------
|
|
631
|
+
fraction : ndarray, dtype=float, shape=(n,3) or shape=(m,n,3)
|
|
632
|
+
The fractions of the box vectors.
|
|
633
|
+
|
|
634
|
+
See Also
|
|
635
|
+
--------
|
|
636
|
+
fraction_to_coord : The reverse operation.
|
|
637
|
+
|
|
638
|
+
Examples
|
|
639
|
+
--------
|
|
640
|
+
|
|
641
|
+
>>> box = np.array([[5,0,0], [0,5,0], [0,5,5]], dtype=float)
|
|
642
|
+
>>> coord = np.array(
|
|
643
|
+
... [[1,1,1], [10,0,0], [0,0,10], [-5,2,1]],
|
|
644
|
+
... dtype=float
|
|
645
|
+
... )
|
|
646
|
+
>>> print(coord)
|
|
647
|
+
[[ 1. 1. 1.]
|
|
648
|
+
[10. 0. 0.]
|
|
649
|
+
[ 0. 0. 10.]
|
|
650
|
+
[-5. 2. 1.]]
|
|
651
|
+
>>> fractions = coord_to_fraction(coord, box)
|
|
652
|
+
>>> print(fractions)
|
|
653
|
+
[[ 0.2 0.0 0.2]
|
|
654
|
+
[ 2.0 0.0 0.0]
|
|
655
|
+
[ 0.0 -2.0 2.0]
|
|
656
|
+
[-1.0 0.2 0.2]]
|
|
657
|
+
"""
|
|
658
|
+
return np.matmul(coord, linalg.inv(box))
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
def fraction_to_coord(fraction, box):
|
|
662
|
+
"""
|
|
663
|
+
Transform fractions of box vectors to coordinates.
|
|
664
|
+
|
|
665
|
+
This is the reverse operation of :func:`coord_to_fraction()`.
|
|
666
|
+
|
|
667
|
+
Parameters
|
|
668
|
+
----------
|
|
669
|
+
fraction : ndarray, dtype=float, shape=(n,3) or shape=(m,n,3)
|
|
670
|
+
The fractions of the box vectors for one or multiple models.
|
|
671
|
+
box : ndarray, dtype=float, shape=(3,3) or shape=(m,3,3)
|
|
672
|
+
The box(es) for one or multiple models.
|
|
673
|
+
When `coord` is given for multiple models, :attr:`box` must be
|
|
674
|
+
given for multiple models as well.
|
|
675
|
+
|
|
676
|
+
Returns
|
|
677
|
+
-------
|
|
678
|
+
coord : ndarray, dtype=float, shape=(n,3) or shape=(m,n,3)
|
|
679
|
+
The coordinates.
|
|
680
|
+
|
|
681
|
+
See Also
|
|
682
|
+
--------
|
|
683
|
+
coord_to_fraction : The reverse operation.
|
|
684
|
+
"""
|
|
685
|
+
return np.matmul(fraction, box)
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
def is_orthogonal(box):
|
|
689
|
+
"""
|
|
690
|
+
Check, whether a box or multiple boxes is/are orthogonal.
|
|
691
|
+
|
|
692
|
+
A box is orthogonal when the dot product of all box vectors with
|
|
693
|
+
each other is 0.
|
|
694
|
+
|
|
695
|
+
Parameters
|
|
696
|
+
----------
|
|
697
|
+
box : ndarray, dtype=float, shape=(3,3) or shape=(m,3,3)
|
|
698
|
+
A single box or multiple boxes.
|
|
699
|
+
|
|
700
|
+
Returns
|
|
701
|
+
-------
|
|
702
|
+
is_orthgonal : bool or ndarray, shape=(m,), dtype=bool
|
|
703
|
+
True, if the box vectors are orthogonal, false otherwise.
|
|
704
|
+
|
|
705
|
+
Notes
|
|
706
|
+
-----
|
|
707
|
+
Due to possible numerical errors, this function also evaluates two
|
|
708
|
+
vectors as orthogonal, when their dot product is not exactly zero,
|
|
709
|
+
but it is within a small tolerance (:math:`10^{-6}`).
|
|
710
|
+
"""
|
|
711
|
+
# Fix numerical errors, as values, that are actually 0,
|
|
712
|
+
# might not be calculated as such
|
|
713
|
+
tol = 1e-6
|
|
714
|
+
return (
|
|
715
|
+
(np.abs(vector_dot(box[..., 0, :], box[..., 1, :])) < tol)
|
|
716
|
+
& (np.abs(vector_dot(box[..., 0, :], box[..., 2, :])) < tol)
|
|
717
|
+
& (np.abs(vector_dot(box[..., 1, :], box[..., 2, :])) < tol)
|
|
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)
|