biotite 1.5.0__cp312-cp312-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.

Files changed (354) 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 +216 -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 +447 -0
  22. biotite/application/tantan/__init__.py +12 -0
  23. biotite/application/tantan/app.py +199 -0
  24. biotite/application/util.py +77 -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 +208 -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/afdb/__init__.py +12 -0
  34. biotite/database/afdb/download.py +197 -0
  35. biotite/database/entrez/__init__.py +15 -0
  36. biotite/database/entrez/check.py +60 -0
  37. biotite/database/entrez/dbnames.py +101 -0
  38. biotite/database/entrez/download.py +228 -0
  39. biotite/database/entrez/key.py +44 -0
  40. biotite/database/entrez/query.py +263 -0
  41. biotite/database/error.py +16 -0
  42. biotite/database/pubchem/__init__.py +21 -0
  43. biotite/database/pubchem/download.py +258 -0
  44. biotite/database/pubchem/error.py +30 -0
  45. biotite/database/pubchem/query.py +819 -0
  46. biotite/database/pubchem/throttle.py +98 -0
  47. biotite/database/rcsb/__init__.py +13 -0
  48. biotite/database/rcsb/download.py +161 -0
  49. biotite/database/rcsb/query.py +963 -0
  50. biotite/database/uniprot/__init__.py +13 -0
  51. biotite/database/uniprot/check.py +40 -0
  52. biotite/database/uniprot/download.py +126 -0
  53. biotite/database/uniprot/query.py +292 -0
  54. biotite/file.py +244 -0
  55. biotite/interface/__init__.py +19 -0
  56. biotite/interface/openmm/__init__.py +20 -0
  57. biotite/interface/openmm/state.py +93 -0
  58. biotite/interface/openmm/system.py +227 -0
  59. biotite/interface/pymol/__init__.py +201 -0
  60. biotite/interface/pymol/cgo.py +346 -0
  61. biotite/interface/pymol/convert.py +185 -0
  62. biotite/interface/pymol/display.py +267 -0
  63. biotite/interface/pymol/object.py +1228 -0
  64. biotite/interface/pymol/shapes.py +178 -0
  65. biotite/interface/pymol/startup.py +169 -0
  66. biotite/interface/rdkit/__init__.py +19 -0
  67. biotite/interface/rdkit/mol.py +490 -0
  68. biotite/interface/version.py +94 -0
  69. biotite/interface/warning.py +19 -0
  70. biotite/sequence/__init__.py +84 -0
  71. biotite/sequence/align/__init__.py +199 -0
  72. biotite/sequence/align/alignment.py +702 -0
  73. biotite/sequence/align/banded.cpython-312-x86_64-linux-gnu.so +0 -0
  74. biotite/sequence/align/banded.pyx +652 -0
  75. biotite/sequence/align/buckets.py +71 -0
  76. biotite/sequence/align/cigar.py +425 -0
  77. biotite/sequence/align/kmeralphabet.cpython-312-x86_64-linux-gnu.so +0 -0
  78. biotite/sequence/align/kmeralphabet.pyx +595 -0
  79. biotite/sequence/align/kmersimilarity.cpython-312-x86_64-linux-gnu.so +0 -0
  80. biotite/sequence/align/kmersimilarity.pyx +233 -0
  81. biotite/sequence/align/kmertable.cpython-312-x86_64-linux-gnu.so +0 -0
  82. biotite/sequence/align/kmertable.pyx +3411 -0
  83. biotite/sequence/align/localgapped.cpython-312-x86_64-linux-gnu.so +0 -0
  84. biotite/sequence/align/localgapped.pyx +892 -0
  85. biotite/sequence/align/localungapped.cpython-312-x86_64-linux-gnu.so +0 -0
  86. biotite/sequence/align/localungapped.pyx +279 -0
  87. biotite/sequence/align/matrix.py +631 -0
  88. biotite/sequence/align/matrix_data/3Di.mat +24 -0
  89. biotite/sequence/align/matrix_data/BLOSUM100.mat +31 -0
  90. biotite/sequence/align/matrix_data/BLOSUM30.mat +31 -0
  91. biotite/sequence/align/matrix_data/BLOSUM35.mat +31 -0
  92. biotite/sequence/align/matrix_data/BLOSUM40.mat +31 -0
  93. biotite/sequence/align/matrix_data/BLOSUM45.mat +31 -0
  94. biotite/sequence/align/matrix_data/BLOSUM50.mat +31 -0
  95. biotite/sequence/align/matrix_data/BLOSUM50_13p.mat +25 -0
  96. biotite/sequence/align/matrix_data/BLOSUM50_14.3.mat +25 -0
  97. biotite/sequence/align/matrix_data/BLOSUM50_5.0.mat +25 -0
  98. biotite/sequence/align/matrix_data/BLOSUM55.mat +31 -0
  99. biotite/sequence/align/matrix_data/BLOSUM60.mat +31 -0
  100. biotite/sequence/align/matrix_data/BLOSUM62.mat +31 -0
  101. biotite/sequence/align/matrix_data/BLOSUM62_13p.mat +25 -0
  102. biotite/sequence/align/matrix_data/BLOSUM62_14.3.mat +25 -0
  103. biotite/sequence/align/matrix_data/BLOSUM62_5.0.mat +25 -0
  104. biotite/sequence/align/matrix_data/BLOSUM65.mat +31 -0
  105. biotite/sequence/align/matrix_data/BLOSUM70.mat +31 -0
  106. biotite/sequence/align/matrix_data/BLOSUM75.mat +31 -0
  107. biotite/sequence/align/matrix_data/BLOSUM80.mat +31 -0
  108. biotite/sequence/align/matrix_data/BLOSUM85.mat +31 -0
  109. biotite/sequence/align/matrix_data/BLOSUM90.mat +31 -0
  110. biotite/sequence/align/matrix_data/BLOSUMN.mat +31 -0
  111. biotite/sequence/align/matrix_data/CorBLOSUM49_5.0.mat +25 -0
  112. biotite/sequence/align/matrix_data/CorBLOSUM57_13p.mat +25 -0
  113. biotite/sequence/align/matrix_data/CorBLOSUM57_14.3.mat +25 -0
  114. biotite/sequence/align/matrix_data/CorBLOSUM61_5.0.mat +25 -0
  115. biotite/sequence/align/matrix_data/CorBLOSUM66_13p.mat +25 -0
  116. biotite/sequence/align/matrix_data/CorBLOSUM67_14.3.mat +25 -0
  117. biotite/sequence/align/matrix_data/DAYHOFF.mat +32 -0
  118. biotite/sequence/align/matrix_data/GONNET.mat +26 -0
  119. biotite/sequence/align/matrix_data/IDENTITY.mat +25 -0
  120. biotite/sequence/align/matrix_data/MATCH.mat +25 -0
  121. biotite/sequence/align/matrix_data/NUC.mat +25 -0
  122. biotite/sequence/align/matrix_data/PAM10.mat +34 -0
  123. biotite/sequence/align/matrix_data/PAM100.mat +34 -0
  124. biotite/sequence/align/matrix_data/PAM110.mat +34 -0
  125. biotite/sequence/align/matrix_data/PAM120.mat +34 -0
  126. biotite/sequence/align/matrix_data/PAM130.mat +34 -0
  127. biotite/sequence/align/matrix_data/PAM140.mat +34 -0
  128. biotite/sequence/align/matrix_data/PAM150.mat +34 -0
  129. biotite/sequence/align/matrix_data/PAM160.mat +34 -0
  130. biotite/sequence/align/matrix_data/PAM170.mat +34 -0
  131. biotite/sequence/align/matrix_data/PAM180.mat +34 -0
  132. biotite/sequence/align/matrix_data/PAM190.mat +34 -0
  133. biotite/sequence/align/matrix_data/PAM20.mat +34 -0
  134. biotite/sequence/align/matrix_data/PAM200.mat +34 -0
  135. biotite/sequence/align/matrix_data/PAM210.mat +34 -0
  136. biotite/sequence/align/matrix_data/PAM220.mat +34 -0
  137. biotite/sequence/align/matrix_data/PAM230.mat +34 -0
  138. biotite/sequence/align/matrix_data/PAM240.mat +34 -0
  139. biotite/sequence/align/matrix_data/PAM250.mat +34 -0
  140. biotite/sequence/align/matrix_data/PAM260.mat +34 -0
  141. biotite/sequence/align/matrix_data/PAM270.mat +34 -0
  142. biotite/sequence/align/matrix_data/PAM280.mat +34 -0
  143. biotite/sequence/align/matrix_data/PAM290.mat +34 -0
  144. biotite/sequence/align/matrix_data/PAM30.mat +34 -0
  145. biotite/sequence/align/matrix_data/PAM300.mat +34 -0
  146. biotite/sequence/align/matrix_data/PAM310.mat +34 -0
  147. biotite/sequence/align/matrix_data/PAM320.mat +34 -0
  148. biotite/sequence/align/matrix_data/PAM330.mat +34 -0
  149. biotite/sequence/align/matrix_data/PAM340.mat +34 -0
  150. biotite/sequence/align/matrix_data/PAM350.mat +34 -0
  151. biotite/sequence/align/matrix_data/PAM360.mat +34 -0
  152. biotite/sequence/align/matrix_data/PAM370.mat +34 -0
  153. biotite/sequence/align/matrix_data/PAM380.mat +34 -0
  154. biotite/sequence/align/matrix_data/PAM390.mat +34 -0
  155. biotite/sequence/align/matrix_data/PAM40.mat +34 -0
  156. biotite/sequence/align/matrix_data/PAM400.mat +34 -0
  157. biotite/sequence/align/matrix_data/PAM410.mat +34 -0
  158. biotite/sequence/align/matrix_data/PAM420.mat +34 -0
  159. biotite/sequence/align/matrix_data/PAM430.mat +34 -0
  160. biotite/sequence/align/matrix_data/PAM440.mat +34 -0
  161. biotite/sequence/align/matrix_data/PAM450.mat +34 -0
  162. biotite/sequence/align/matrix_data/PAM460.mat +34 -0
  163. biotite/sequence/align/matrix_data/PAM470.mat +34 -0
  164. biotite/sequence/align/matrix_data/PAM480.mat +34 -0
  165. biotite/sequence/align/matrix_data/PAM490.mat +34 -0
  166. biotite/sequence/align/matrix_data/PAM50.mat +34 -0
  167. biotite/sequence/align/matrix_data/PAM500.mat +34 -0
  168. biotite/sequence/align/matrix_data/PAM60.mat +34 -0
  169. biotite/sequence/align/matrix_data/PAM70.mat +34 -0
  170. biotite/sequence/align/matrix_data/PAM80.mat +34 -0
  171. biotite/sequence/align/matrix_data/PAM90.mat +34 -0
  172. biotite/sequence/align/matrix_data/PB.license +21 -0
  173. biotite/sequence/align/matrix_data/PB.mat +18 -0
  174. biotite/sequence/align/matrix_data/RBLOSUM52_5.0.mat +25 -0
  175. biotite/sequence/align/matrix_data/RBLOSUM59_13p.mat +25 -0
  176. biotite/sequence/align/matrix_data/RBLOSUM59_14.3.mat +25 -0
  177. biotite/sequence/align/matrix_data/RBLOSUM64_5.0.mat +25 -0
  178. biotite/sequence/align/matrix_data/RBLOSUM69_13p.mat +25 -0
  179. biotite/sequence/align/matrix_data/RBLOSUM69_14.3.mat +25 -0
  180. biotite/sequence/align/multiple.cpython-312-x86_64-linux-gnu.so +0 -0
  181. biotite/sequence/align/multiple.pyx +619 -0
  182. biotite/sequence/align/pairwise.cpython-312-x86_64-linux-gnu.so +0 -0
  183. biotite/sequence/align/pairwise.pyx +585 -0
  184. biotite/sequence/align/permutation.cpython-312-x86_64-linux-gnu.so +0 -0
  185. biotite/sequence/align/permutation.pyx +313 -0
  186. biotite/sequence/align/primes.txt +821 -0
  187. biotite/sequence/align/selector.cpython-312-x86_64-linux-gnu.so +0 -0
  188. biotite/sequence/align/selector.pyx +954 -0
  189. biotite/sequence/align/statistics.py +264 -0
  190. biotite/sequence/align/tracetable.cpython-312-x86_64-linux-gnu.so +0 -0
  191. biotite/sequence/align/tracetable.pxd +64 -0
  192. biotite/sequence/align/tracetable.pyx +370 -0
  193. biotite/sequence/alphabet.py +555 -0
  194. biotite/sequence/annotation.py +836 -0
  195. biotite/sequence/codec.cpython-312-x86_64-linux-gnu.so +0 -0
  196. biotite/sequence/codec.pyx +155 -0
  197. biotite/sequence/codon.py +476 -0
  198. biotite/sequence/codon_tables.txt +202 -0
  199. biotite/sequence/graphics/__init__.py +33 -0
  200. biotite/sequence/graphics/alignment.py +1101 -0
  201. biotite/sequence/graphics/color_schemes/3di_flower.json +48 -0
  202. biotite/sequence/graphics/color_schemes/autumn.json +51 -0
  203. biotite/sequence/graphics/color_schemes/blossom.json +51 -0
  204. biotite/sequence/graphics/color_schemes/clustalx_dna.json +11 -0
  205. biotite/sequence/graphics/color_schemes/clustalx_protein.json +28 -0
  206. biotite/sequence/graphics/color_schemes/flower.json +51 -0
  207. biotite/sequence/graphics/color_schemes/jalview_buried.json +31 -0
  208. biotite/sequence/graphics/color_schemes/jalview_hydrophobicity.json +31 -0
  209. biotite/sequence/graphics/color_schemes/jalview_prop_helix.json +31 -0
  210. biotite/sequence/graphics/color_schemes/jalview_prop_strand.json +31 -0
  211. biotite/sequence/graphics/color_schemes/jalview_prop_turn.json +31 -0
  212. biotite/sequence/graphics/color_schemes/jalview_taylor.json +28 -0
  213. biotite/sequence/graphics/color_schemes/jalview_zappo.json +28 -0
  214. biotite/sequence/graphics/color_schemes/ocean.json +51 -0
  215. biotite/sequence/graphics/color_schemes/pb_flower.json +40 -0
  216. biotite/sequence/graphics/color_schemes/rainbow_dna.json +11 -0
  217. biotite/sequence/graphics/color_schemes/rainbow_protein.json +30 -0
  218. biotite/sequence/graphics/color_schemes/spring.json +51 -0
  219. biotite/sequence/graphics/color_schemes/sunset.json +51 -0
  220. biotite/sequence/graphics/color_schemes/wither.json +51 -0
  221. biotite/sequence/graphics/colorschemes.py +170 -0
  222. biotite/sequence/graphics/dendrogram.py +231 -0
  223. biotite/sequence/graphics/features.py +544 -0
  224. biotite/sequence/graphics/logo.py +102 -0
  225. biotite/sequence/graphics/plasmid.py +712 -0
  226. biotite/sequence/io/__init__.py +12 -0
  227. biotite/sequence/io/fasta/__init__.py +22 -0
  228. biotite/sequence/io/fasta/convert.py +283 -0
  229. biotite/sequence/io/fasta/file.py +265 -0
  230. biotite/sequence/io/fastq/__init__.py +19 -0
  231. biotite/sequence/io/fastq/convert.py +117 -0
  232. biotite/sequence/io/fastq/file.py +507 -0
  233. biotite/sequence/io/genbank/__init__.py +17 -0
  234. biotite/sequence/io/genbank/annotation.py +269 -0
  235. biotite/sequence/io/genbank/file.py +573 -0
  236. biotite/sequence/io/genbank/metadata.py +336 -0
  237. biotite/sequence/io/genbank/sequence.py +173 -0
  238. biotite/sequence/io/general.py +201 -0
  239. biotite/sequence/io/gff/__init__.py +26 -0
  240. biotite/sequence/io/gff/convert.py +128 -0
  241. biotite/sequence/io/gff/file.py +449 -0
  242. biotite/sequence/phylo/__init__.py +36 -0
  243. biotite/sequence/phylo/nj.cpython-312-x86_64-linux-gnu.so +0 -0
  244. biotite/sequence/phylo/nj.pyx +221 -0
  245. biotite/sequence/phylo/tree.cpython-312-x86_64-linux-gnu.so +0 -0
  246. biotite/sequence/phylo/tree.pyx +1169 -0
  247. biotite/sequence/phylo/upgma.cpython-312-x86_64-linux-gnu.so +0 -0
  248. biotite/sequence/phylo/upgma.pyx +164 -0
  249. biotite/sequence/profile.py +561 -0
  250. biotite/sequence/search.py +117 -0
  251. biotite/sequence/seqtypes.py +720 -0
  252. biotite/sequence/sequence.py +373 -0
  253. biotite/setup_ccd.py +197 -0
  254. biotite/structure/__init__.py +135 -0
  255. biotite/structure/alphabet/__init__.py +25 -0
  256. biotite/structure/alphabet/encoder.py +332 -0
  257. biotite/structure/alphabet/encoder_weights_3di.kerasify +0 -0
  258. biotite/structure/alphabet/i3d.py +109 -0
  259. biotite/structure/alphabet/layers.py +86 -0
  260. biotite/structure/alphabet/pb.license +21 -0
  261. biotite/structure/alphabet/pb.py +170 -0
  262. biotite/structure/alphabet/unkerasify.py +128 -0
  263. biotite/structure/atoms.py +1562 -0
  264. biotite/structure/basepairs.py +1403 -0
  265. biotite/structure/bonds.cpython-312-x86_64-linux-gnu.so +0 -0
  266. biotite/structure/bonds.pyx +2036 -0
  267. biotite/structure/box.py +724 -0
  268. biotite/structure/celllist.cpython-312-x86_64-linux-gnu.so +0 -0
  269. biotite/structure/celllist.pyx +864 -0
  270. biotite/structure/chains.py +310 -0
  271. biotite/structure/charges.cpython-312-x86_64-linux-gnu.so +0 -0
  272. biotite/structure/charges.pyx +520 -0
  273. biotite/structure/compare.py +683 -0
  274. biotite/structure/density.py +109 -0
  275. biotite/structure/dotbracket.py +213 -0
  276. biotite/structure/error.py +39 -0
  277. biotite/structure/filter.py +591 -0
  278. biotite/structure/geometry.py +817 -0
  279. biotite/structure/graphics/__init__.py +13 -0
  280. biotite/structure/graphics/atoms.py +243 -0
  281. biotite/structure/graphics/rna.py +298 -0
  282. biotite/structure/hbond.py +425 -0
  283. biotite/structure/info/__init__.py +24 -0
  284. biotite/structure/info/atom_masses.json +121 -0
  285. biotite/structure/info/atoms.py +98 -0
  286. biotite/structure/info/bonds.py +149 -0
  287. biotite/structure/info/ccd.py +200 -0
  288. biotite/structure/info/components.bcif +0 -0
  289. biotite/structure/info/groups.py +128 -0
  290. biotite/structure/info/masses.py +121 -0
  291. biotite/structure/info/misc.py +137 -0
  292. biotite/structure/info/radii.py +267 -0
  293. biotite/structure/info/standardize.py +185 -0
  294. biotite/structure/integrity.py +213 -0
  295. biotite/structure/io/__init__.py +29 -0
  296. biotite/structure/io/dcd/__init__.py +13 -0
  297. biotite/structure/io/dcd/file.py +67 -0
  298. biotite/structure/io/general.py +243 -0
  299. biotite/structure/io/gro/__init__.py +14 -0
  300. biotite/structure/io/gro/file.py +343 -0
  301. biotite/structure/io/mol/__init__.py +20 -0
  302. biotite/structure/io/mol/convert.py +112 -0
  303. biotite/structure/io/mol/ctab.py +420 -0
  304. biotite/structure/io/mol/header.py +120 -0
  305. biotite/structure/io/mol/mol.py +149 -0
  306. biotite/structure/io/mol/sdf.py +940 -0
  307. biotite/structure/io/netcdf/__init__.py +13 -0
  308. biotite/structure/io/netcdf/file.py +64 -0
  309. biotite/structure/io/pdb/__init__.py +20 -0
  310. biotite/structure/io/pdb/convert.py +389 -0
  311. biotite/structure/io/pdb/file.py +1380 -0
  312. biotite/structure/io/pdb/hybrid36.cpython-312-x86_64-linux-gnu.so +0 -0
  313. biotite/structure/io/pdb/hybrid36.pyx +242 -0
  314. biotite/structure/io/pdbqt/__init__.py +15 -0
  315. biotite/structure/io/pdbqt/convert.py +113 -0
  316. biotite/structure/io/pdbqt/file.py +688 -0
  317. biotite/structure/io/pdbx/__init__.py +23 -0
  318. biotite/structure/io/pdbx/bcif.py +674 -0
  319. biotite/structure/io/pdbx/cif.py +1091 -0
  320. biotite/structure/io/pdbx/component.py +251 -0
  321. biotite/structure/io/pdbx/compress.py +362 -0
  322. biotite/structure/io/pdbx/convert.py +2113 -0
  323. biotite/structure/io/pdbx/encoding.cpython-312-x86_64-linux-gnu.so +0 -0
  324. biotite/structure/io/pdbx/encoding.pyx +1078 -0
  325. biotite/structure/io/trajfile.py +696 -0
  326. biotite/structure/io/trr/__init__.py +13 -0
  327. biotite/structure/io/trr/file.py +43 -0
  328. biotite/structure/io/util.py +38 -0
  329. biotite/structure/io/xtc/__init__.py +13 -0
  330. biotite/structure/io/xtc/file.py +43 -0
  331. biotite/structure/mechanics.py +72 -0
  332. biotite/structure/molecules.py +337 -0
  333. biotite/structure/pseudoknots.py +622 -0
  334. biotite/structure/rdf.py +245 -0
  335. biotite/structure/repair.py +302 -0
  336. biotite/structure/residues.py +716 -0
  337. biotite/structure/rings.py +451 -0
  338. biotite/structure/sasa.cpython-312-x86_64-linux-gnu.so +0 -0
  339. biotite/structure/sasa.pyx +322 -0
  340. biotite/structure/segments.py +328 -0
  341. biotite/structure/sequence.py +110 -0
  342. biotite/structure/spacegroups.json +1567 -0
  343. biotite/structure/spacegroups.license +26 -0
  344. biotite/structure/sse.py +306 -0
  345. biotite/structure/superimpose.py +511 -0
  346. biotite/structure/tm.py +581 -0
  347. biotite/structure/transform.py +736 -0
  348. biotite/structure/util.py +160 -0
  349. biotite/version.py +34 -0
  350. biotite/visualize.py +375 -0
  351. biotite-1.5.0.dist-info/METADATA +162 -0
  352. biotite-1.5.0.dist-info/RECORD +354 -0
  353. biotite-1.5.0.dist-info/WHEEL +6 -0
  354. biotite-1.5.0.dist-info/licenses/LICENSE.rst +30 -0
@@ -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)