biotite 1.1.0__cp313-cp313-macosx_10_13_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.

Files changed (332) hide show
  1. biotite/__init__.py +18 -0
  2. biotite/application/__init__.py +69 -0
  3. biotite/application/application.py +276 -0
  4. biotite/application/autodock/__init__.py +12 -0
  5. biotite/application/autodock/app.py +500 -0
  6. biotite/application/blast/__init__.py +14 -0
  7. biotite/application/blast/alignment.py +92 -0
  8. biotite/application/blast/webapp.py +428 -0
  9. biotite/application/clustalo/__init__.py +12 -0
  10. biotite/application/clustalo/app.py +223 -0
  11. biotite/application/dssp/__init__.py +12 -0
  12. biotite/application/dssp/app.py +159 -0
  13. biotite/application/localapp.py +342 -0
  14. biotite/application/mafft/__init__.py +12 -0
  15. biotite/application/mafft/app.py +116 -0
  16. biotite/application/msaapp.py +363 -0
  17. biotite/application/muscle/__init__.py +13 -0
  18. biotite/application/muscle/app3.py +227 -0
  19. biotite/application/muscle/app5.py +163 -0
  20. biotite/application/sra/__init__.py +18 -0
  21. biotite/application/sra/app.py +452 -0
  22. biotite/application/tantan/__init__.py +12 -0
  23. biotite/application/tantan/app.py +199 -0
  24. biotite/application/util.py +57 -0
  25. biotite/application/viennarna/__init__.py +18 -0
  26. biotite/application/viennarna/rnaalifold.py +310 -0
  27. biotite/application/viennarna/rnafold.py +254 -0
  28. biotite/application/viennarna/rnaplot.py +206 -0
  29. biotite/application/viennarna/util.py +77 -0
  30. biotite/application/webapp.py +76 -0
  31. biotite/copyable.py +71 -0
  32. biotite/database/__init__.py +23 -0
  33. biotite/database/entrez/__init__.py +15 -0
  34. biotite/database/entrez/check.py +60 -0
  35. biotite/database/entrez/dbnames.py +91 -0
  36. biotite/database/entrez/download.py +229 -0
  37. biotite/database/entrez/key.py +44 -0
  38. biotite/database/entrez/query.py +262 -0
  39. biotite/database/error.py +16 -0
  40. biotite/database/pubchem/__init__.py +21 -0
  41. biotite/database/pubchem/download.py +258 -0
  42. biotite/database/pubchem/error.py +20 -0
  43. biotite/database/pubchem/query.py +830 -0
  44. biotite/database/pubchem/throttle.py +98 -0
  45. biotite/database/rcsb/__init__.py +13 -0
  46. biotite/database/rcsb/download.py +159 -0
  47. biotite/database/rcsb/query.py +964 -0
  48. biotite/database/uniprot/__init__.py +13 -0
  49. biotite/database/uniprot/check.py +40 -0
  50. biotite/database/uniprot/download.py +129 -0
  51. biotite/database/uniprot/query.py +293 -0
  52. biotite/file.py +232 -0
  53. biotite/sequence/__init__.py +84 -0
  54. biotite/sequence/align/__init__.py +203 -0
  55. biotite/sequence/align/alignment.py +680 -0
  56. biotite/sequence/align/banded.cpython-313-darwin.so +0 -0
  57. biotite/sequence/align/banded.pyx +652 -0
  58. biotite/sequence/align/buckets.py +71 -0
  59. biotite/sequence/align/cigar.py +425 -0
  60. biotite/sequence/align/kmeralphabet.cpython-313-darwin.so +0 -0
  61. biotite/sequence/align/kmeralphabet.pyx +595 -0
  62. biotite/sequence/align/kmersimilarity.cpython-313-darwin.so +0 -0
  63. biotite/sequence/align/kmersimilarity.pyx +233 -0
  64. biotite/sequence/align/kmertable.cpython-313-darwin.so +0 -0
  65. biotite/sequence/align/kmertable.pyx +3411 -0
  66. biotite/sequence/align/localgapped.cpython-313-darwin.so +0 -0
  67. biotite/sequence/align/localgapped.pyx +892 -0
  68. biotite/sequence/align/localungapped.cpython-313-darwin.so +0 -0
  69. biotite/sequence/align/localungapped.pyx +279 -0
  70. biotite/sequence/align/matrix.py +622 -0
  71. biotite/sequence/align/matrix_data/3Di.mat +24 -0
  72. biotite/sequence/align/matrix_data/BLOSUM100.mat +31 -0
  73. biotite/sequence/align/matrix_data/BLOSUM30.mat +31 -0
  74. biotite/sequence/align/matrix_data/BLOSUM35.mat +31 -0
  75. biotite/sequence/align/matrix_data/BLOSUM40.mat +31 -0
  76. biotite/sequence/align/matrix_data/BLOSUM45.mat +31 -0
  77. biotite/sequence/align/matrix_data/BLOSUM50.mat +31 -0
  78. biotite/sequence/align/matrix_data/BLOSUM50_13p.mat +25 -0
  79. biotite/sequence/align/matrix_data/BLOSUM50_14.3.mat +25 -0
  80. biotite/sequence/align/matrix_data/BLOSUM50_5.0.mat +25 -0
  81. biotite/sequence/align/matrix_data/BLOSUM55.mat +31 -0
  82. biotite/sequence/align/matrix_data/BLOSUM60.mat +31 -0
  83. biotite/sequence/align/matrix_data/BLOSUM62.mat +31 -0
  84. biotite/sequence/align/matrix_data/BLOSUM62_13p.mat +25 -0
  85. biotite/sequence/align/matrix_data/BLOSUM62_14.3.mat +25 -0
  86. biotite/sequence/align/matrix_data/BLOSUM62_5.0.mat +25 -0
  87. biotite/sequence/align/matrix_data/BLOSUM65.mat +31 -0
  88. biotite/sequence/align/matrix_data/BLOSUM70.mat +31 -0
  89. biotite/sequence/align/matrix_data/BLOSUM75.mat +31 -0
  90. biotite/sequence/align/matrix_data/BLOSUM80.mat +31 -0
  91. biotite/sequence/align/matrix_data/BLOSUM85.mat +31 -0
  92. biotite/sequence/align/matrix_data/BLOSUM90.mat +31 -0
  93. biotite/sequence/align/matrix_data/BLOSUMN.mat +31 -0
  94. biotite/sequence/align/matrix_data/CorBLOSUM49_5.0.mat +25 -0
  95. biotite/sequence/align/matrix_data/CorBLOSUM57_13p.mat +25 -0
  96. biotite/sequence/align/matrix_data/CorBLOSUM57_14.3.mat +25 -0
  97. biotite/sequence/align/matrix_data/CorBLOSUM61_5.0.mat +25 -0
  98. biotite/sequence/align/matrix_data/CorBLOSUM66_13p.mat +25 -0
  99. biotite/sequence/align/matrix_data/CorBLOSUM67_14.3.mat +25 -0
  100. biotite/sequence/align/matrix_data/DAYHOFF.mat +32 -0
  101. biotite/sequence/align/matrix_data/GONNET.mat +26 -0
  102. biotite/sequence/align/matrix_data/IDENTITY.mat +25 -0
  103. biotite/sequence/align/matrix_data/MATCH.mat +25 -0
  104. biotite/sequence/align/matrix_data/NUC.mat +25 -0
  105. biotite/sequence/align/matrix_data/PAM10.mat +34 -0
  106. biotite/sequence/align/matrix_data/PAM100.mat +34 -0
  107. biotite/sequence/align/matrix_data/PAM110.mat +34 -0
  108. biotite/sequence/align/matrix_data/PAM120.mat +34 -0
  109. biotite/sequence/align/matrix_data/PAM130.mat +34 -0
  110. biotite/sequence/align/matrix_data/PAM140.mat +34 -0
  111. biotite/sequence/align/matrix_data/PAM150.mat +34 -0
  112. biotite/sequence/align/matrix_data/PAM160.mat +34 -0
  113. biotite/sequence/align/matrix_data/PAM170.mat +34 -0
  114. biotite/sequence/align/matrix_data/PAM180.mat +34 -0
  115. biotite/sequence/align/matrix_data/PAM190.mat +34 -0
  116. biotite/sequence/align/matrix_data/PAM20.mat +34 -0
  117. biotite/sequence/align/matrix_data/PAM200.mat +34 -0
  118. biotite/sequence/align/matrix_data/PAM210.mat +34 -0
  119. biotite/sequence/align/matrix_data/PAM220.mat +34 -0
  120. biotite/sequence/align/matrix_data/PAM230.mat +34 -0
  121. biotite/sequence/align/matrix_data/PAM240.mat +34 -0
  122. biotite/sequence/align/matrix_data/PAM250.mat +34 -0
  123. biotite/sequence/align/matrix_data/PAM260.mat +34 -0
  124. biotite/sequence/align/matrix_data/PAM270.mat +34 -0
  125. biotite/sequence/align/matrix_data/PAM280.mat +34 -0
  126. biotite/sequence/align/matrix_data/PAM290.mat +34 -0
  127. biotite/sequence/align/matrix_data/PAM30.mat +34 -0
  128. biotite/sequence/align/matrix_data/PAM300.mat +34 -0
  129. biotite/sequence/align/matrix_data/PAM310.mat +34 -0
  130. biotite/sequence/align/matrix_data/PAM320.mat +34 -0
  131. biotite/sequence/align/matrix_data/PAM330.mat +34 -0
  132. biotite/sequence/align/matrix_data/PAM340.mat +34 -0
  133. biotite/sequence/align/matrix_data/PAM350.mat +34 -0
  134. biotite/sequence/align/matrix_data/PAM360.mat +34 -0
  135. biotite/sequence/align/matrix_data/PAM370.mat +34 -0
  136. biotite/sequence/align/matrix_data/PAM380.mat +34 -0
  137. biotite/sequence/align/matrix_data/PAM390.mat +34 -0
  138. biotite/sequence/align/matrix_data/PAM40.mat +34 -0
  139. biotite/sequence/align/matrix_data/PAM400.mat +34 -0
  140. biotite/sequence/align/matrix_data/PAM410.mat +34 -0
  141. biotite/sequence/align/matrix_data/PAM420.mat +34 -0
  142. biotite/sequence/align/matrix_data/PAM430.mat +34 -0
  143. biotite/sequence/align/matrix_data/PAM440.mat +34 -0
  144. biotite/sequence/align/matrix_data/PAM450.mat +34 -0
  145. biotite/sequence/align/matrix_data/PAM460.mat +34 -0
  146. biotite/sequence/align/matrix_data/PAM470.mat +34 -0
  147. biotite/sequence/align/matrix_data/PAM480.mat +34 -0
  148. biotite/sequence/align/matrix_data/PAM490.mat +34 -0
  149. biotite/sequence/align/matrix_data/PAM50.mat +34 -0
  150. biotite/sequence/align/matrix_data/PAM500.mat +34 -0
  151. biotite/sequence/align/matrix_data/PAM60.mat +34 -0
  152. biotite/sequence/align/matrix_data/PAM70.mat +34 -0
  153. biotite/sequence/align/matrix_data/PAM80.mat +34 -0
  154. biotite/sequence/align/matrix_data/PAM90.mat +34 -0
  155. biotite/sequence/align/matrix_data/PB.license +21 -0
  156. biotite/sequence/align/matrix_data/PB.mat +18 -0
  157. biotite/sequence/align/matrix_data/RBLOSUM52_5.0.mat +25 -0
  158. biotite/sequence/align/matrix_data/RBLOSUM59_13p.mat +25 -0
  159. biotite/sequence/align/matrix_data/RBLOSUM59_14.3.mat +25 -0
  160. biotite/sequence/align/matrix_data/RBLOSUM64_5.0.mat +25 -0
  161. biotite/sequence/align/matrix_data/RBLOSUM69_13p.mat +25 -0
  162. biotite/sequence/align/matrix_data/RBLOSUM69_14.3.mat +25 -0
  163. biotite/sequence/align/multiple.cpython-313-darwin.so +0 -0
  164. biotite/sequence/align/multiple.pyx +620 -0
  165. biotite/sequence/align/pairwise.cpython-313-darwin.so +0 -0
  166. biotite/sequence/align/pairwise.pyx +587 -0
  167. biotite/sequence/align/permutation.cpython-313-darwin.so +0 -0
  168. biotite/sequence/align/permutation.pyx +313 -0
  169. biotite/sequence/align/primes.txt +821 -0
  170. biotite/sequence/align/selector.cpython-313-darwin.so +0 -0
  171. biotite/sequence/align/selector.pyx +954 -0
  172. biotite/sequence/align/statistics.py +264 -0
  173. biotite/sequence/align/tracetable.cpython-313-darwin.so +0 -0
  174. biotite/sequence/align/tracetable.pxd +64 -0
  175. biotite/sequence/align/tracetable.pyx +370 -0
  176. biotite/sequence/alphabet.py +555 -0
  177. biotite/sequence/annotation.py +830 -0
  178. biotite/sequence/codec.cpython-313-darwin.so +0 -0
  179. biotite/sequence/codec.pyx +155 -0
  180. biotite/sequence/codon.py +477 -0
  181. biotite/sequence/codon_tables.txt +202 -0
  182. biotite/sequence/graphics/__init__.py +33 -0
  183. biotite/sequence/graphics/alignment.py +1115 -0
  184. biotite/sequence/graphics/color_schemes/3di_flower.json +48 -0
  185. biotite/sequence/graphics/color_schemes/autumn.json +51 -0
  186. biotite/sequence/graphics/color_schemes/blossom.json +51 -0
  187. biotite/sequence/graphics/color_schemes/clustalx_dna.json +11 -0
  188. biotite/sequence/graphics/color_schemes/clustalx_protein.json +28 -0
  189. biotite/sequence/graphics/color_schemes/flower.json +51 -0
  190. biotite/sequence/graphics/color_schemes/jalview_buried.json +31 -0
  191. biotite/sequence/graphics/color_schemes/jalview_hydrophobicity.json +31 -0
  192. biotite/sequence/graphics/color_schemes/jalview_prop_helix.json +31 -0
  193. biotite/sequence/graphics/color_schemes/jalview_prop_strand.json +31 -0
  194. biotite/sequence/graphics/color_schemes/jalview_prop_turn.json +31 -0
  195. biotite/sequence/graphics/color_schemes/jalview_taylor.json +28 -0
  196. biotite/sequence/graphics/color_schemes/jalview_zappo.json +28 -0
  197. biotite/sequence/graphics/color_schemes/ocean.json +51 -0
  198. biotite/sequence/graphics/color_schemes/pb_flower.json +40 -0
  199. biotite/sequence/graphics/color_schemes/rainbow_dna.json +11 -0
  200. biotite/sequence/graphics/color_schemes/rainbow_protein.json +30 -0
  201. biotite/sequence/graphics/color_schemes/spring.json +51 -0
  202. biotite/sequence/graphics/color_schemes/sunset.json +51 -0
  203. biotite/sequence/graphics/color_schemes/wither.json +51 -0
  204. biotite/sequence/graphics/colorschemes.py +170 -0
  205. biotite/sequence/graphics/dendrogram.py +229 -0
  206. biotite/sequence/graphics/features.py +544 -0
  207. biotite/sequence/graphics/logo.py +104 -0
  208. biotite/sequence/graphics/plasmid.py +712 -0
  209. biotite/sequence/io/__init__.py +12 -0
  210. biotite/sequence/io/fasta/__init__.py +22 -0
  211. biotite/sequence/io/fasta/convert.py +284 -0
  212. biotite/sequence/io/fasta/file.py +265 -0
  213. biotite/sequence/io/fastq/__init__.py +19 -0
  214. biotite/sequence/io/fastq/convert.py +117 -0
  215. biotite/sequence/io/fastq/file.py +507 -0
  216. biotite/sequence/io/genbank/__init__.py +17 -0
  217. biotite/sequence/io/genbank/annotation.py +269 -0
  218. biotite/sequence/io/genbank/file.py +573 -0
  219. biotite/sequence/io/genbank/metadata.py +336 -0
  220. biotite/sequence/io/genbank/sequence.py +171 -0
  221. biotite/sequence/io/general.py +201 -0
  222. biotite/sequence/io/gff/__init__.py +26 -0
  223. biotite/sequence/io/gff/convert.py +128 -0
  224. biotite/sequence/io/gff/file.py +450 -0
  225. biotite/sequence/phylo/__init__.py +36 -0
  226. biotite/sequence/phylo/nj.cpython-313-darwin.so +0 -0
  227. biotite/sequence/phylo/nj.pyx +221 -0
  228. biotite/sequence/phylo/tree.cpython-313-darwin.so +0 -0
  229. biotite/sequence/phylo/tree.pyx +1169 -0
  230. biotite/sequence/phylo/upgma.cpython-313-darwin.so +0 -0
  231. biotite/sequence/phylo/upgma.pyx +164 -0
  232. biotite/sequence/profile.py +567 -0
  233. biotite/sequence/search.py +118 -0
  234. biotite/sequence/seqtypes.py +713 -0
  235. biotite/sequence/sequence.py +374 -0
  236. biotite/setup_ccd.py +197 -0
  237. biotite/structure/__init__.py +133 -0
  238. biotite/structure/alphabet/__init__.py +25 -0
  239. biotite/structure/alphabet/encoder.py +332 -0
  240. biotite/structure/alphabet/encoder_weights_3di.kerasify +0 -0
  241. biotite/structure/alphabet/i3d.py +110 -0
  242. biotite/structure/alphabet/layers.py +86 -0
  243. biotite/structure/alphabet/pb.license +21 -0
  244. biotite/structure/alphabet/pb.py +171 -0
  245. biotite/structure/alphabet/unkerasify.py +122 -0
  246. biotite/structure/atoms.py +1554 -0
  247. biotite/structure/basepairs.py +1404 -0
  248. biotite/structure/bonds.cpython-313-darwin.so +0 -0
  249. biotite/structure/bonds.pyx +1972 -0
  250. biotite/structure/box.py +588 -0
  251. biotite/structure/celllist.cpython-313-darwin.so +0 -0
  252. biotite/structure/celllist.pyx +849 -0
  253. biotite/structure/chains.py +314 -0
  254. biotite/structure/charges.cpython-313-darwin.so +0 -0
  255. biotite/structure/charges.pyx +520 -0
  256. biotite/structure/compare.py +274 -0
  257. biotite/structure/density.py +109 -0
  258. biotite/structure/dotbracket.py +214 -0
  259. biotite/structure/error.py +39 -0
  260. biotite/structure/filter.py +590 -0
  261. biotite/structure/geometry.py +655 -0
  262. biotite/structure/graphics/__init__.py +13 -0
  263. biotite/structure/graphics/atoms.py +243 -0
  264. biotite/structure/graphics/rna.py +295 -0
  265. biotite/structure/hbond.py +428 -0
  266. biotite/structure/info/__init__.py +24 -0
  267. biotite/structure/info/atom_masses.json +121 -0
  268. biotite/structure/info/atoms.py +81 -0
  269. biotite/structure/info/bonds.py +149 -0
  270. biotite/structure/info/ccd.py +202 -0
  271. biotite/structure/info/components.bcif +0 -0
  272. biotite/structure/info/groups.py +131 -0
  273. biotite/structure/info/masses.py +121 -0
  274. biotite/structure/info/misc.py +138 -0
  275. biotite/structure/info/radii.py +197 -0
  276. biotite/structure/info/standardize.py +186 -0
  277. biotite/structure/integrity.py +215 -0
  278. biotite/structure/io/__init__.py +29 -0
  279. biotite/structure/io/dcd/__init__.py +13 -0
  280. biotite/structure/io/dcd/file.py +67 -0
  281. biotite/structure/io/general.py +243 -0
  282. biotite/structure/io/gro/__init__.py +14 -0
  283. biotite/structure/io/gro/file.py +344 -0
  284. biotite/structure/io/mol/__init__.py +20 -0
  285. biotite/structure/io/mol/convert.py +112 -0
  286. biotite/structure/io/mol/ctab.py +415 -0
  287. biotite/structure/io/mol/header.py +120 -0
  288. biotite/structure/io/mol/mol.py +149 -0
  289. biotite/structure/io/mol/sdf.py +914 -0
  290. biotite/structure/io/netcdf/__init__.py +13 -0
  291. biotite/structure/io/netcdf/file.py +64 -0
  292. biotite/structure/io/pdb/__init__.py +20 -0
  293. biotite/structure/io/pdb/convert.py +307 -0
  294. biotite/structure/io/pdb/file.py +1290 -0
  295. biotite/structure/io/pdb/hybrid36.cpython-313-darwin.so +0 -0
  296. biotite/structure/io/pdb/hybrid36.pyx +242 -0
  297. biotite/structure/io/pdbqt/__init__.py +15 -0
  298. biotite/structure/io/pdbqt/convert.py +113 -0
  299. biotite/structure/io/pdbqt/file.py +688 -0
  300. biotite/structure/io/pdbx/__init__.py +23 -0
  301. biotite/structure/io/pdbx/bcif.py +656 -0
  302. biotite/structure/io/pdbx/cif.py +1075 -0
  303. biotite/structure/io/pdbx/component.py +245 -0
  304. biotite/structure/io/pdbx/compress.py +321 -0
  305. biotite/structure/io/pdbx/convert.py +1745 -0
  306. biotite/structure/io/pdbx/encoding.cpython-313-darwin.so +0 -0
  307. biotite/structure/io/pdbx/encoding.pyx +1031 -0
  308. biotite/structure/io/trajfile.py +693 -0
  309. biotite/structure/io/trr/__init__.py +13 -0
  310. biotite/structure/io/trr/file.py +43 -0
  311. biotite/structure/io/xtc/__init__.py +13 -0
  312. biotite/structure/io/xtc/file.py +43 -0
  313. biotite/structure/mechanics.py +73 -0
  314. biotite/structure/molecules.py +352 -0
  315. biotite/structure/pseudoknots.py +628 -0
  316. biotite/structure/rdf.py +245 -0
  317. biotite/structure/repair.py +304 -0
  318. biotite/structure/residues.py +572 -0
  319. biotite/structure/sasa.cpython-313-darwin.so +0 -0
  320. biotite/structure/sasa.pyx +322 -0
  321. biotite/structure/segments.py +178 -0
  322. biotite/structure/sequence.py +111 -0
  323. biotite/structure/sse.py +308 -0
  324. biotite/structure/superimpose.py +689 -0
  325. biotite/structure/transform.py +530 -0
  326. biotite/structure/util.py +168 -0
  327. biotite/version.py +16 -0
  328. biotite/visualize.py +265 -0
  329. biotite-1.1.0.dist-info/METADATA +190 -0
  330. biotite-1.1.0.dist-info/RECORD +332 -0
  331. biotite-1.1.0.dist-info/WHEEL +4 -0
  332. biotite-1.1.0.dist-info/licenses/LICENSE.rst +30 -0
@@ -0,0 +1,530 @@
1
+ # This source code is part of the Biotite package and is distributed
2
+ # under the 3-Clause BSD License. Please see 'LICENSE.rst' for further
3
+ # information.
4
+
5
+ """
6
+ This module provides different transformations#
7
+ that can be applied on structures.
8
+ """
9
+
10
+ __name__ = "biotite.structure"
11
+ __author__ = "Patrick Kunzmann", "Claude J. Rogers"
12
+ __all__ = [
13
+ "translate",
14
+ "rotate",
15
+ "rotate_centered",
16
+ "rotate_about_axis",
17
+ "orient_principal_components",
18
+ "align_vectors",
19
+ ]
20
+
21
+ import numpy as np
22
+ from biotite.structure.atoms import Atom, AtomArray, AtomArrayStack, coord
23
+ from biotite.structure.geometry import centroid
24
+ from biotite.structure.util import matrix_rotate, norm_vector, vector_dot
25
+
26
+
27
+ def translate(atoms, vector):
28
+ """
29
+ Translate the given atoms or coordinates by a given vector.
30
+
31
+ Parameters
32
+ ----------
33
+ atoms : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
34
+ The atoms of which the coordinates are transformed.
35
+ The coordinates can be directly provided as :class:`ndarray`.
36
+ vector: array-like, shape=(3,) or shape=(n,3) or shape=(m,n,3)
37
+ The translation vector :math:`(x, y, z)`.
38
+
39
+ Returns
40
+ -------
41
+ transformed : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
42
+ A copy of the input atoms or coordinates, translated by the
43
+ given vector.
44
+ """
45
+ positions = coord(atoms).copy()
46
+ vector = np.asarray(vector)
47
+
48
+ if vector.shape[-1] != 3:
49
+ raise ValueError("Translation vector must contain 3 coordinates")
50
+ positions += vector
51
+ return _put_back(atoms, positions)
52
+
53
+
54
+ def rotate(atoms, angles):
55
+ """
56
+ Rotate the given atoms or coordinates about the *x*, *y* and *z*
57
+ axes by given angles.
58
+
59
+ The rotations are centered at the origin and are performed
60
+ sequentially in the order *x*, *y*, *z*.
61
+
62
+ Parameters
63
+ ----------
64
+ atoms : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
65
+ The atoms of which the coordinates are transformed.
66
+ The coordinates can be directly provided as :class:`ndarray`.
67
+ angles: array-like, length=3
68
+ The rotation angles in radians around *x*, *y* and *z*.
69
+
70
+ Returns
71
+ -------
72
+ transformed : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
73
+ A copy of the input atoms or coordinates, rotated by the given
74
+ angles.
75
+
76
+ See Also
77
+ --------
78
+ rotate_centered
79
+ rotate_about_axis
80
+
81
+ Examples
82
+ --------
83
+ Rotation about the *z*-axis by 90 degrees:
84
+
85
+ >>> position = np.array([2.0, 0.0, 0.0])
86
+ >>> rotated = rotate(position, angles=(0, 0, 0.5*np.pi))
87
+ >>> print(rotated)
88
+ [1.225e-16 2.000e+00 0.000e+00]
89
+ """
90
+ from numpy import cos, sin
91
+
92
+ # Check if "angles" contains 3 angles for all dimensions
93
+ if len(angles) != 3:
94
+ raise ValueError("Translation vector must be container of length 3")
95
+ # Create rotation matrices for all 3 dimensions
96
+ rot_x = np.array(
97
+ [
98
+ [1, 0, 0],
99
+ [0, cos(angles[0]), -sin(angles[0])],
100
+ [0, sin(angles[0]), cos(angles[0])],
101
+ ]
102
+ )
103
+
104
+ rot_y = np.array(
105
+ [
106
+ [cos(angles[1]), 0, sin(angles[1])],
107
+ [0, 1, 0],
108
+ [-sin(angles[1]), 0, cos(angles[1])],
109
+ ]
110
+ )
111
+
112
+ rot_z = np.array(
113
+ [
114
+ [cos(angles[2]), -sin(angles[2]), 0],
115
+ [sin(angles[2]), cos(angles[2]), 0],
116
+ [0, 0, 1],
117
+ ]
118
+ )
119
+
120
+ positions = coord(atoms).copy()
121
+ positions = matrix_rotate(positions, rot_z @ rot_y @ rot_x)
122
+
123
+ return _put_back(atoms, positions)
124
+
125
+
126
+ def rotate_centered(atoms, angles):
127
+ """
128
+ Rotate the given atoms or coordinates about the *x*, *y* and *z*
129
+ axes by given angles.
130
+
131
+ The rotations are centered at the centroid of the corresponding
132
+ structure and are performed sequentially in the order *x*, *y*, *z*.
133
+
134
+ Parameters
135
+ ----------
136
+ atoms : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
137
+ The atoms of which the coordinates are transformed.
138
+ The coordinates can be directly provided as :class:`ndarray`.
139
+ angles: array-like, length=3
140
+ The rotation angles in radians around axes *x*, *y* and *z*.
141
+
142
+ Returns
143
+ -------
144
+ transformed : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
145
+ A copy of the input atoms or coordinates, rotated by the given
146
+ angles.
147
+
148
+ See Also
149
+ --------
150
+ rotate
151
+ rotate_about_axis
152
+ """
153
+ if len(coord(atoms).shape) == 1:
154
+ # Single value -> centered rotation does not change coordinates
155
+ return atoms.copy()
156
+
157
+ # Rotation around centroid requires moving centroid to origin
158
+ center = coord(centroid(atoms))
159
+ # 'centroid()' removes the second last dimesion
160
+ # -> add dimension again to ensure correct translation
161
+ center = center[..., np.newaxis, :]
162
+ translated = translate(atoms, -center)
163
+ rotated = rotate(translated, angles)
164
+ translated_back = translate(rotated, center)
165
+ return translated_back
166
+
167
+
168
+ def rotate_about_axis(atoms, axis, angle, support=None):
169
+ """
170
+ Rotate the given atoms or coordinates about a given axis by a given
171
+ angle.
172
+
173
+ Parameters
174
+ ----------
175
+ atoms : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
176
+ The atoms of which the coordinates are transformed.
177
+ The coordinates can be directly provided as :class:`ndarray`.
178
+ axis : array-like, length=3
179
+ A vector representing the direction of the rotation axis.
180
+ The length of the vector is irrelevant.
181
+ angle : float
182
+ The rotation angle in radians.
183
+ support : array-like, length=3, optional
184
+ An optional support vector for the rotation axis, i.e. the
185
+ center of the rotation.
186
+ By default, the center of the rotation is at *(0,0,0)*.
187
+
188
+ Returns
189
+ -------
190
+ transformed : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
191
+ A copy of the input atoms or coordinates, rotated about the
192
+ given axis.
193
+
194
+ See Also
195
+ --------
196
+ rotate
197
+ rotate_centered
198
+
199
+ Examples
200
+ --------
201
+ Rotation about a custom axis on the *y*-*z*-plane by 90 degrees:
202
+
203
+ >>> position = np.array([2.0, 0.0, 0.0])
204
+ >>> axis = [0.0, 1.0, 1.0]
205
+ >>> rotated = rotate_about_axis(position, axis, angle=0.5*np.pi)
206
+ >>> print(rotated)
207
+ [ 1.225e-16 1.414e+00 -1.414e+00]
208
+ """
209
+ positions = coord(atoms).copy()
210
+ if support is not None:
211
+ # Transform coordinates
212
+ # so that the axis support vector is at (0,0,0)
213
+ positions -= np.asarray(support)
214
+
215
+ # Normalize axis
216
+ axis = np.asarray(axis, dtype=np.float32).copy()
217
+ if np.linalg.norm(axis) == 0:
218
+ raise ValueError("Length of the rotation axis is 0")
219
+ norm_vector(axis)
220
+ # Save some interim values, that are used repeatedly in the
221
+ # rotation matrix, for clarity and to save computation time
222
+ sin_a = np.sin(angle)
223
+ cos_a = np.cos(angle)
224
+ icos_a = 1 - cos_a
225
+ x = axis[..., 0]
226
+ y = axis[..., 1]
227
+ z = axis[..., 2]
228
+ # Rotation matrix is taken from
229
+ # https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
230
+ rot_matrix = np.array(
231
+ [
232
+ [
233
+ cos_a + icos_a * x**2,
234
+ icos_a * x * y - z * sin_a,
235
+ icos_a * x * z + y * sin_a,
236
+ ],
237
+ [
238
+ icos_a * x * y + z * sin_a,
239
+ cos_a + icos_a * y**2,
240
+ icos_a * y * z - x * sin_a,
241
+ ],
242
+ [
243
+ icos_a * x * z - y * sin_a,
244
+ icos_a * y * z + x * sin_a,
245
+ cos_a + icos_a * z**2,
246
+ ],
247
+ ]
248
+ )
249
+
250
+ # For proper rotation reshape into a maximum of 2 dimensions
251
+ orig_ndim = positions.ndim
252
+ if orig_ndim > 2:
253
+ orig_shape = positions.shape
254
+ positions = positions.reshape(-1, 3)
255
+ # Apply rotation
256
+ positions = np.dot(rot_matrix, positions.T).T
257
+ # Reshape back into original shape
258
+ if orig_ndim > 2:
259
+ positions = positions.reshape(*orig_shape)
260
+
261
+ if support is not None:
262
+ # Transform coordinates back to original support vector position
263
+ positions += np.asarray(support)
264
+
265
+ return _put_back(atoms, positions)
266
+
267
+
268
+ def orient_principal_components(atoms, order=None):
269
+ """
270
+ Translate and rotate the atoms to be centered at the origin with
271
+ the principal axes aligned to the Cartesian axes, as specified by
272
+ the `order` parameter. By default, x, y, z.
273
+
274
+ By default, the resulting coordinates have the highest variance in
275
+ the x-axis and the lowest variance on the z-axis. Setting the `order`
276
+ parameter will change the direction of the highest variance.
277
+ For example, ``order=(2, 1, 0)`` results in highest variance along the
278
+ z-axis and lowest along the x-axis.
279
+
280
+ Parameters
281
+ ----------
282
+ atoms : AtomArray or ndarray, shape=(n,3)
283
+ The atoms of which the coordinates are transformed.
284
+ The coordinates can be directly provided as :class:`ndarray`.
285
+ order : array-like, length=3
286
+ The order of decreasing variance. Setting `order` to ``(2, 0, 1)``
287
+ results in highest variance along the y-axis and lowest along
288
+ the x-axis. Default = ``(0, 1, 2)``.
289
+
290
+ Returns
291
+ -------
292
+ AtomArray or ndarray, shape=(n,3)
293
+ The atoms with coordinates centered at the orgin and aligned with
294
+ xyz axes.
295
+
296
+ See Also
297
+ --------
298
+ rotate_centered
299
+ rotate_about_axis
300
+
301
+ Examples
302
+ --------
303
+ Align principal components to xyz axes (default), or specify the order
304
+ of variance.
305
+
306
+ >>> print("original variance =", atom_array.coord.var(axis=0))
307
+ original variance = [26.517 20.009 9.325]
308
+ >>> moved = orient_principal_components(atom_array)
309
+ >>> print("moved variance =", moved.coord.var(axis=0))
310
+ moved variance = [28.906 18.495 8.450]
311
+ >>> # Note the increase in variance along the x-axis
312
+ >>> # Specifying the order keyword changes the orientation
313
+ >>> moved_z = orient_principal_components(atom_array, order=(2, 1, 0))
314
+ >>> print("moved (zyx) variance =", moved_z.coord.var(axis=0))
315
+ moved (zyx) variance = [ 8.450 18.495 28.906]
316
+ """
317
+ # Check user input
318
+ coords = coord(atoms)
319
+ if coords.ndim != 2:
320
+ raise ValueError(f"Expected input shape of (n, 3), got {coords.shape}.")
321
+ row, col = coords.shape
322
+ if (row < 3) or (col != 3):
323
+ raise ValueError(
324
+ f"Expected at least 3 entries, {row} given,"
325
+ f" and 3 dimensions, {col} given."
326
+ )
327
+ if order is None:
328
+ order = np.array([0, 1, 2])
329
+ else:
330
+ order = np.asarray(order, dtype=int)
331
+ if order.shape != (3,):
332
+ raise ValueError(f"Expected order to have shape (3,), not {order.shape}")
333
+ if not (np.sort(order) == np.arange(3)).all():
334
+ raise ValueError("Expected order to contain [0, 1, 2].")
335
+
336
+ # place centroid of the atoms at the origin
337
+ centered = coords - coords.mean(axis=0)
338
+
339
+ # iterate a few times to ensure the ideal rotation has been applied
340
+ identity = np.eye(3)
341
+ MAX_ITER = 50
342
+ for _ in range(MAX_ITER):
343
+ # PCA, W is the component matrix, s ~ explained variance
344
+ _, sigma, components = np.linalg.svd(centered)
345
+
346
+ # sort 1st, 2nd, 3rd pca compontents along x, y, z
347
+ idx = sigma.argsort()[::-1][order]
348
+ ident = np.eye(3)[:, idx]
349
+
350
+ # Run the Kabsch algorithm to orient principal components
351
+ # along the x, y, z axes
352
+ v, _, wt = np.linalg.svd(components.T @ ident)
353
+
354
+ if np.linalg.det(v) * np.linalg.det(wt) < -0:
355
+ v[:, -1] *= -1
356
+ # Calculate rotation matrix
357
+ rotation = v @ wt
358
+ if np.isclose(rotation, identity, atol=1e-5).all():
359
+ break
360
+ # Apply rotation, keep molecule centered on the origin
361
+ centered = centered @ rotation
362
+ return _put_back(atoms, centered)
363
+
364
+
365
+ def align_vectors(
366
+ atoms,
367
+ origin_direction,
368
+ target_direction,
369
+ origin_position=None,
370
+ target_position=None,
371
+ ):
372
+ """
373
+ Apply a transformation to atoms or coordinates, that would transfer
374
+ a origin vector to a target vector.
375
+
376
+ At first the transformation (translation and rotation), that is
377
+ necessary to align the origin vector to the target vector is
378
+ calculated.
379
+ This means, that the application of the transformation on the
380
+ origin vector would give the target vector.
381
+ Then the same transformation is applied to the given
382
+ atoms/coordinates.
383
+
384
+ Parameters
385
+ ----------
386
+ atoms : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
387
+ The atoms of which the coordinates are transformed.
388
+ The coordinates can be directly provided as :class:`ndarray`.
389
+ origin_direction, target_direction : array-like, length=3
390
+ The vectors representing the direction of the origin or target,
391
+ respectively.
392
+ The length of the vectors is irrelevant.
393
+ origin_position, target_position : array-like, length=3, optional
394
+ Optional support vectors for the origin or target, respectively.
395
+ By default, origin and target start at *(0,0,0)*.
396
+
397
+ Returns
398
+ -------
399
+ transformed : Atom or AtomArray or AtomArrayStack or ndarray, shape=(3,) or shape=(n,3) or shape=(m,n,3)
400
+ A copy of the input atoms or coordinates with the applied
401
+ transformation.
402
+
403
+ See Also
404
+ --------
405
+ rotate
406
+ rotate_centered
407
+
408
+ Examples
409
+ --------
410
+ Align two different residues at their CA-CB bond, i.e. the CA and CB
411
+ position of both residues should be equal:
412
+
413
+ >>> first_residue = atom_array[atom_array.res_id == 1]
414
+ >>> second_residue = atom_array[atom_array.res_id == 2]
415
+ >>> first_residue_ca = first_residue[first_residue.atom_name == "CA"]
416
+ >>> first_residue_cb = first_residue[first_residue.atom_name == "CB"]
417
+ >>> second_residue_ca = second_residue[second_residue.atom_name == "CA"]
418
+ >>> second_residue_cb = second_residue[second_residue.atom_name == "CB"]
419
+ >>> first_residue = align_vectors(
420
+ ... first_residue,
421
+ ... origin_direction = first_residue_cb.coord - first_residue_ca.coord,
422
+ ... target_direction = second_residue_cb.coord - second_residue_ca.coord,
423
+ ... origin_position = first_residue_ca.coord,
424
+ ... target_position = second_residue_ca.coord
425
+ ... )
426
+ >>> # The CA and CB coordinates of both residues are now almost equal
427
+ >>> print(first_residue)
428
+ A 1 ASN N N -5.549 3.788 -1.125
429
+ A 1 ASN CA C -4.923 4.002 -2.452
430
+ A 1 ASN C C -3.877 2.949 -2.808
431
+ A 1 ASN O O -4.051 2.292 -3.825
432
+ A 1 ASN CB C -4.413 5.445 -2.618
433
+ A 1 ASN CG C -5.593 6.413 -2.670
434
+ A 1 ASN OD1 O -6.738 5.988 -2.651
435
+ A 1 ASN ND2 N -5.362 7.711 -2.695
436
+ A 1 ASN H1 H -5.854 2.830 -1.023
437
+ A 1 ASN H2 H -4.902 4.017 -0.382
438
+ A 1 ASN H3 H -6.357 4.397 -1.047
439
+ A 1 ASN HA H -5.711 3.870 -3.198
440
+ A 1 ASN HB2 H -3.781 5.697 -1.788
441
+ A 1 ASN HB3 H -3.860 5.526 -3.556
442
+ A 1 ASN HD21 H -4.440 8.115 -2.680
443
+ A 1 ASN HD22 H -6.190 8.284 -2.750
444
+ >>> print(second_residue)
445
+ A 2 LEU N N -6.379 4.031 -2.228
446
+ A 2 LEU CA C -4.923 4.002 -2.452
447
+ A 2 LEU C C -4.136 3.187 -1.404
448
+ A 2 LEU O O -3.391 2.274 -1.760
449
+ A 2 LEU CB C -4.411 5.450 -2.619
450
+ A 2 LEU CG C -4.795 6.450 -1.495
451
+ A 2 LEU CD1 C -3.612 6.803 -0.599
452
+ A 2 LEU CD2 C -5.351 7.748 -2.084
453
+ A 2 LEU H H -6.821 4.923 -2.394
454
+ A 2 LEU HA H -4.750 3.494 -3.403
455
+ A 2 LEU HB2 H -3.340 5.414 -2.672
456
+ A 2 LEU HB3 H -4.813 5.817 -3.564
457
+ A 2 LEU HG H -5.568 6.022 -0.858
458
+ A 2 LEU HD11 H -3.207 5.905 -0.146
459
+ A 2 LEU HD12 H -2.841 7.304 -1.183
460
+ A 2 LEU HD13 H -3.929 7.477 0.197
461
+ A 2 LEU HD21 H -4.607 8.209 -2.736
462
+ A 2 LEU HD22 H -6.255 7.544 -2.657
463
+ A 2 LEU HD23 H -5.592 8.445 -1.281
464
+ """
465
+ origin_direction = np.asarray(origin_direction, dtype=np.float32).squeeze()
466
+ target_direction = np.asarray(target_direction, dtype=np.float32).squeeze()
467
+ # check that original and target direction are vectors of shape (3,)
468
+ if origin_direction.shape != (3,):
469
+ raise ValueError(
470
+ f"Expected origin vector to have shape (3,), "
471
+ f"got {origin_direction.shape}"
472
+ )
473
+ if target_direction.shape != (3,):
474
+ raise ValueError(
475
+ f"Expected target vector to have shape (3,), "
476
+ f"got {target_direction.shape}"
477
+ )
478
+ if np.linalg.norm(origin_direction) == 0:
479
+ raise ValueError("Length of the origin vector is 0")
480
+ if np.linalg.norm(target_direction) == 0:
481
+ raise ValueError("Length of the target vector is 0")
482
+ if origin_position is not None:
483
+ origin_position = np.asarray(origin_position, dtype=np.float32)
484
+ if target_position is not None:
485
+ target_position = np.asarray(target_position, dtype=np.float32)
486
+
487
+ positions = coord(atoms).copy()
488
+ if origin_position is not None:
489
+ # Transform coordinates
490
+ # so that the position of the origin vector is at (0,0,0)
491
+ positions -= origin_position
492
+
493
+ # Normalize direction vectors
494
+ origin_direction = origin_direction.copy()
495
+ norm_vector(origin_direction)
496
+ target_direction = target_direction.copy()
497
+ norm_vector(target_direction)
498
+ # Formula is taken from
499
+ # https://math.stackexchange.com/questions/180418/calculate-rotation-matrix-to-align-vector-a-to-vector-b-in-3d/476311#476311
500
+ vx, vy, vz = np.cross(origin_direction, target_direction)
501
+ v_c = np.array([[0, -vz, vy], [vz, 0, -vx], [-vy, vx, 0]], dtype=float)
502
+ cos_a = vector_dot(origin_direction, target_direction)
503
+ if np.all(cos_a == -1):
504
+ raise ValueError(
505
+ "Direction vectors are point into opposite directions, "
506
+ "cannot calculate rotation matrix"
507
+ )
508
+ rot_matrix = np.identity(3) + v_c + (v_c @ v_c) / (1 + cos_a)
509
+
510
+ positions = matrix_rotate(positions, rot_matrix)
511
+
512
+ if target_position is not None:
513
+ # Transform coordinates to position of the target vector
514
+ positions += target_position
515
+
516
+ return _put_back(atoms, positions)
517
+
518
+
519
+ def _put_back(input_atoms, transformed):
520
+ """
521
+ Put the altered coordinates back into the :class:`Atom`,
522
+ :class:`AtomArray` or :class:`AtomArrayStack`, if the input was one
523
+ of these types.
524
+ """
525
+ if isinstance(input_atoms, (Atom, AtomArray, AtomArrayStack)):
526
+ moved_atoms = input_atoms.copy()
527
+ moved_atoms.coord = transformed
528
+ return moved_atoms
529
+ else:
530
+ return transformed
@@ -0,0 +1,168 @@
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
+ Utility functions for in internal use in `Bio.Structure` package
7
+ """
8
+
9
+ __name__ = "biotite.structure"
10
+ __author__ = "Patrick Kunzmann"
11
+ __all__ = [
12
+ "vector_dot",
13
+ "norm_vector",
14
+ "distance",
15
+ "matrix_rotate",
16
+ "coord_for_atom_name_per_residue",
17
+ ]
18
+
19
+ import numpy as np
20
+ from biotite.structure.atoms import AtomArrayStack
21
+ from biotite.structure.error import BadStructureError
22
+ from biotite.structure.residues import get_residue_masks, get_residue_starts
23
+
24
+
25
+ def vector_dot(v1, v2):
26
+ """
27
+ Calculate vector dot product of two vectors.
28
+
29
+ Parameters
30
+ ----------
31
+ v1,v2 : ndarray
32
+ The arrays to calculate the product from.
33
+ The vectors are represented by the last axis.
34
+
35
+ Returns
36
+ -------
37
+ product : float or ndarray
38
+ Scalar product over the last dimension of the arrays.
39
+ """
40
+ return (v1 * v2).sum(axis=-1)
41
+
42
+
43
+ def norm_vector(v):
44
+ """
45
+ Normalise a vector.
46
+
47
+ Parameters
48
+ ----------
49
+ v : ndarray
50
+ The array containg the vector(s).
51
+ The vectors are represented by the last axis.
52
+ """
53
+ factor = np.linalg.norm(v, axis=-1)
54
+ if isinstance(factor, np.ndarray):
55
+ v /= factor[..., np.newaxis]
56
+ else:
57
+ v /= factor
58
+
59
+
60
+ def distance(v1, v2):
61
+ """
62
+ Calculate the distance between two position vectors.
63
+
64
+ Parameters
65
+ ----------
66
+ v1,v2 : ndarray
67
+ The arrays to calculate the product from.
68
+ The vectors are represented by the last axis.
69
+
70
+ Returns
71
+ -------
72
+ product : float or ndarray
73
+ Vector distance over the last dimension of the array.
74
+ """
75
+ dif = v1 - v2
76
+ return np.sqrt((dif * dif).sum(axis=-1))
77
+
78
+
79
+ def matrix_rotate(v, matrix):
80
+ """
81
+ Perform a rotation using a rotation matrix.
82
+
83
+ Parameters
84
+ ----------
85
+ v : ndarray
86
+ The coordinates to rotate.
87
+ matrix : ndarray
88
+ The rotation matrix.
89
+
90
+ Returns
91
+ -------
92
+ rotated : ndarray
93
+ The rotated coordinates.
94
+ """
95
+ # For proper rotation reshape into a maximum of 2 dimensions
96
+ orig_ndim = v.ndim
97
+ if orig_ndim > 2:
98
+ orig_shape = v.shape
99
+ v = v.reshape(-1, 3)
100
+ # Apply rotation
101
+ v = np.dot(matrix, v.T).T
102
+ # Reshape back into original shape
103
+ if orig_ndim > 2:
104
+ v = v.reshape(*orig_shape)
105
+ return v
106
+
107
+
108
+ def coord_for_atom_name_per_residue(atoms, atom_names, mask=None):
109
+ """
110
+ Get the coordinates of a specific atom for every residue.
111
+
112
+ If a residue does not contain the specified atom, the coordinates are `NaN`.
113
+ If a residue contains multiple atoms with the specified name, an exception is
114
+ raised.
115
+
116
+ Parameters
117
+ ----------
118
+ atoms : AtomArray, shape=(n,) or AtomArrayStack, shape=(m,n)
119
+ The atom array or stack to get the residue-wise coordinates from.
120
+ atom_names : list of str, length=k
121
+ The atom names to get the coordinates for.
122
+ mask : ndarray, shape=(n,), dtype=bool, optional
123
+ A boolean mask to further select valid atoms from `atoms`.
124
+
125
+ Returns
126
+ -------
127
+ coord: ndarray, shape=(k, m, r, 3) or shape=(k, r, 3)
128
+ The coordinates of the specified atom for each residue.
129
+ """
130
+ is_multi_model = isinstance(atoms, AtomArrayStack)
131
+ residue_starts = get_residue_starts(atoms)
132
+ all_residue_masks = get_residue_masks(atoms, residue_starts)
133
+
134
+ if is_multi_model:
135
+ coord = np.full(
136
+ (len(atom_names), atoms.stack_depth(), len(residue_starts), 3),
137
+ np.nan,
138
+ dtype=np.float32,
139
+ )
140
+ else:
141
+ coord = np.full(
142
+ (len(atom_names), len(residue_starts), 3),
143
+ np.nan,
144
+ dtype=np.float32,
145
+ )
146
+
147
+ for i, atom_name in enumerate(atom_names):
148
+ specified_atom_mask = atoms.atom_name == atom_name
149
+ if mask is not None:
150
+ specified_atom_mask &= mask
151
+ all_residue_masks_for_specified_atom = all_residue_masks & specified_atom_mask
152
+ number_of_specified_atoms_per_residue = np.count_nonzero(
153
+ all_residue_masks_for_specified_atom, axis=-1
154
+ )
155
+ if np.any(number_of_specified_atoms_per_residue > 1):
156
+ raise BadStructureError(f"Multiple '{atom_name}' atoms per residue")
157
+ residues_with_specified_atom = number_of_specified_atoms_per_residue == 1
158
+ coord_of_specified_atoms = atoms.coord[..., specified_atom_mask, :]
159
+ if is_multi_model:
160
+ # Swap dimensions due to NumPy's behavior when using advanced indexing
161
+ # (https://numpy.org/devdocs/user/basics.indexing.html#combining-advanced-and-basic-indexing)
162
+ coord[i, ..., residues_with_specified_atom, :] = (
163
+ coord_of_specified_atoms.transpose(1, 0, 2)
164
+ )
165
+ else:
166
+ coord[i, residues_with_specified_atom, :] = coord_of_specified_atoms
167
+
168
+ return coord