biotite 1.5.0__cp311-cp311-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-311-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-311-x86_64-linux-gnu.so +0 -0
  78. biotite/sequence/align/kmeralphabet.pyx +595 -0
  79. biotite/sequence/align/kmersimilarity.cpython-311-x86_64-linux-gnu.so +0 -0
  80. biotite/sequence/align/kmersimilarity.pyx +233 -0
  81. biotite/sequence/align/kmertable.cpython-311-x86_64-linux-gnu.so +0 -0
  82. biotite/sequence/align/kmertable.pyx +3411 -0
  83. biotite/sequence/align/localgapped.cpython-311-x86_64-linux-gnu.so +0 -0
  84. biotite/sequence/align/localgapped.pyx +892 -0
  85. biotite/sequence/align/localungapped.cpython-311-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-311-x86_64-linux-gnu.so +0 -0
  181. biotite/sequence/align/multiple.pyx +619 -0
  182. biotite/sequence/align/pairwise.cpython-311-x86_64-linux-gnu.so +0 -0
  183. biotite/sequence/align/pairwise.pyx +585 -0
  184. biotite/sequence/align/permutation.cpython-311-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-311-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-311-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-311-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-311-x86_64-linux-gnu.so +0 -0
  244. biotite/sequence/phylo/nj.pyx +221 -0
  245. biotite/sequence/phylo/tree.cpython-311-x86_64-linux-gnu.so +0 -0
  246. biotite/sequence/phylo/tree.pyx +1169 -0
  247. biotite/sequence/phylo/upgma.cpython-311-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-311-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-311-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-311-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-311-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-311-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-311-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,688 @@
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
+ __name__ = "biotite.structure.io.pdbqt"
6
+ __author__ = "Patrick Kunzmann, Daniel Bauer"
7
+ __all__ = ["PDBQTFile"]
8
+
9
+ import warnings
10
+ import numpy as np
11
+ from biotite.file import InvalidFileError, TextFile
12
+ from biotite.structure.atoms import AtomArray, AtomArrayStack
13
+ from biotite.structure.bonds import (
14
+ BondList,
15
+ BondType,
16
+ find_connected,
17
+ find_rotatable_bonds,
18
+ )
19
+ from biotite.structure.charges import partial_charges
20
+ from biotite.structure.error import BadStructureError
21
+
22
+ PARAMETRIZED_ELEMENTS = [
23
+ "H",
24
+ "C",
25
+ "N",
26
+ "O",
27
+ "P",
28
+ "S",
29
+ "F",
30
+ "Cl",
31
+ "Br",
32
+ "I",
33
+ "Mg",
34
+ "Ca",
35
+ "Mn",
36
+ "Fe",
37
+ "Zn",
38
+ ]
39
+
40
+
41
+ class PDBQTFile(TextFile):
42
+ """
43
+ This class represents an *AutoDock* PDBQT file.
44
+
45
+ This class only provides rudimentary support for reading/writing
46
+ the pure atom information.
47
+
48
+ EXPERIMENTAL: Future API changes are probable.
49
+
50
+ Examples
51
+ --------
52
+
53
+ Write biotin as flexible ligand into a PDBQT file:
54
+
55
+ >>> import os.path
56
+ >>> ligand = residue("BTN")
57
+ >>> file = PDBQTFile()
58
+ >>> mask = file.set_structure(ligand, rotatable_bonds="all")
59
+ >>> # Print removed nonpolar hydrogen atoms
60
+ >>> print(ligand[~mask])
61
+ HET 0 BTN H101 H 3.745 1.171 0.974
62
+ HET 0 BTN H102 H 4.071 1.343 -0.767
63
+ HET 0 BTN H91 H 2.802 -0.740 -1.211
64
+ HET 0 BTN H92 H 2.476 -0.912 0.530
65
+ HET 0 BTN H81 H 1.289 1.265 0.523
66
+ HET 0 BTN H82 H 1.616 1.437 -1.218
67
+ HET 0 BTN H71 H 0.346 -0.646 -1.662
68
+ HET 0 BTN H72 H 0.020 -0.818 0.079
69
+ HET 0 BTN H2 H -0.838 1.576 -1.627
70
+ HET 0 BTN H61 H -3.797 1.837 1.286
71
+ HET 0 BTN H62 H -3.367 2.738 -0.205
72
+ HET 0 BTN H5 H -4.307 0.812 -1.205
73
+ HET 0 BTN H4 H -2.451 -0.038 -2.252
74
+ >>> print(file)
75
+ ROOT
76
+ HETATM 1 C11 BTN 0 5.089 -0.280 0.173 1.00 0.00 0.258 C
77
+ HETATM 2 O11 BTN 0 4.956 -1.473 0.030 1.00 0.00 -0.264 OA
78
+ ENDROOT
79
+ BRANCH 1 3
80
+ HETATM 3 O12 BTN 0 6.299 0.233 0.444 1.00 0.00 -0.331 OA
81
+ HETATM 17 HO2 BTN 0 7.034 -0.391 0.517 1.00 0.00 0.221 HD
82
+ ENDBRANCH 1 3
83
+ BRANCH 1 4
84
+ HETATM 4 C10 BTN 0 3.896 0.631 0.039 1.00 0.00 0.105 C
85
+ BRANCH 4 5
86
+ HETATM 5 C9 BTN 0 2.651 -0.200 -0.276 1.00 0.00 0.010 C
87
+ BRANCH 5 6
88
+ HETATM 6 C8 BTN 0 1.440 0.725 -0.412 1.00 0.00 0.002 C
89
+ BRANCH 6 7
90
+ HETATM 7 C7 BTN 0 0.196 -0.106 -0.727 1.00 0.00 0.016 C
91
+ BRANCH 7 8
92
+ HETATM 8 C2 BTN 0 -1.015 0.819 -0.863 1.00 0.00 0.065 C
93
+ HETATM 9 S1 BTN 0 -1.419 1.604 0.751 1.00 0.00 -0.154 SA
94
+ HETATM 10 C6 BTN 0 -3.205 1.827 0.371 1.00 0.00 0.090 C
95
+ HETATM 11 C5 BTN 0 -3.530 0.581 -0.476 1.00 0.00 0.091 C
96
+ HETATM 12 N1 BTN 0 -3.970 -0.507 0.412 1.00 0.00 -0.239 NA
97
+ HETATM 13 C3 BTN 0 -3.141 -1.549 0.271 1.00 0.00 0.272 C
98
+ HETATM 14 O3 BTN 0 -3.271 -2.589 0.888 1.00 0.00 -0.259 OA
99
+ HETATM 15 N2 BTN 0 -2.154 -1.343 -0.612 1.00 0.00 -0.239 NA
100
+ HETATM 16 C4 BTN 0 -2.289 0.010 -1.175 1.00 0.00 0.093 C
101
+ HETATM 18 HN1 BTN 0 -4.738 -0.474 1.004 1.00 0.00 0.132 HD
102
+ HETATM 19 HN2 BTN 0 -1.462 -1.982 -0.843 1.00 0.00 0.132 HD
103
+ ENDBRANCH 7 8
104
+ ENDBRANCH 6 7
105
+ ENDBRANCH 5 6
106
+ ENDBRANCH 4 5
107
+ ENDBRANCH 1 4
108
+ TORSDOF 6
109
+ >>> file.write(os.path.join(path_to_directory, "1l2y_mod.pdb"))
110
+ """
111
+
112
+ def get_remarks(self, model=None):
113
+ """
114
+ Get the content of ``REMARKS`` lines.
115
+
116
+ Parameters
117
+ ----------
118
+ model : int, optional
119
+ If this parameter is given, the function will return a
120
+ string from the remarks corresponding to the given
121
+ model number (starting at 1).
122
+ Negative values are used to index models starting from the
123
+ last model insted of the first model.
124
+ If this parameter is omitted, a list of strings
125
+ containing all models will be returned, even if the
126
+ structure contains only one model.
127
+
128
+ Returns
129
+ -------
130
+ lines : str or list of str
131
+ The content of ``REMARKS`` lines, without the leading
132
+ ``'REMARKS'``.
133
+ """
134
+ # Line indices where a new model starts
135
+ model_start_i = np.array(
136
+ [i for i in range(len(self.lines)) if self.lines[i].startswith(("MODEL"))],
137
+ dtype=int,
138
+ )
139
+ # Line indices with ATOM or HETATM records
140
+ remark_line_i = np.array(
141
+ [i for i in range(len(self.lines)) if self.lines[i].startswith("REMARK")],
142
+ dtype=int,
143
+ )
144
+ # Structures containing only one model may omit MODEL record
145
+ # In these cases model starting index is set to 0
146
+ if len(model_start_i) == 0:
147
+ model_start_i = np.array([0])
148
+
149
+ if model is None:
150
+ # Add exclusive end of file
151
+ model_start_i = np.concatenate((model_start_i, [len(self.lines)]))
152
+ remarks = []
153
+ for i in range(len(model_start_i) - 1):
154
+ start = model_start_i[i]
155
+ stop = model_start_i[i + 1]
156
+ model_remark_line_i = remark_line_i[
157
+ (remark_line_i >= start) & (remark_line_i < stop)
158
+ ]
159
+ remarks.append(
160
+ "\n".join([self.lines[i][7:] for i in model_remark_line_i])
161
+ )
162
+ return remarks
163
+
164
+ else:
165
+ last_model = len(model_start_i)
166
+ if model == 0:
167
+ raise ValueError("The model index must not be 0")
168
+ # Negative models mean index starting from last model
169
+ model = last_model + model + 1 if model < 0 else model
170
+
171
+ if model < last_model:
172
+ line_filter = (remark_line_i >= model_start_i[model - 1]) & (
173
+ remark_line_i < model_start_i[model]
174
+ )
175
+ elif model == last_model:
176
+ line_filter = remark_line_i >= model_start_i[model - 1]
177
+ else:
178
+ raise ValueError(
179
+ f"The file has {last_model} models, "
180
+ f"the given model {model} does not exist"
181
+ )
182
+ remark_line_i = remark_line_i[line_filter]
183
+
184
+ # Do not include 'REMARK ' itself -> begin from pos 8
185
+ return "\n".join([self.lines[i][7:] for i in remark_line_i])
186
+
187
+ def get_structure(self, model=None):
188
+ """
189
+ Get an :class:`AtomArray` or :class:`AtomArrayStack` from the
190
+ PDBQT file.
191
+
192
+ Parameters
193
+ ----------
194
+ model : int, optional
195
+ If this parameter is given, the function will return an
196
+ :class:`AtomArray` from the atoms corresponding to the given
197
+ model number (starting at 1).
198
+ Negative values are used to index models starting from the
199
+ last model insted of the first model.
200
+ If this parameter is omitted, an :class:`AtomArrayStack`
201
+ containing all models will be returned, even if the
202
+ structure contains only one model.
203
+
204
+ Returns
205
+ -------
206
+ array : AtomArray or AtomArrayStack
207
+ The return type depends on the `model` parameter.
208
+ """
209
+ # Line indices where a new model starts
210
+ model_start_i = np.array(
211
+ [i for i in range(len(self.lines)) if self.lines[i].startswith(("MODEL"))],
212
+ dtype=int,
213
+ )
214
+ # Line indices with ATOM or HETATM records
215
+ atom_line_i = np.array(
216
+ [
217
+ i
218
+ for i in range(len(self.lines))
219
+ if self.lines[i].startswith(("ATOM", "HETATM"))
220
+ ],
221
+ dtype=int,
222
+ )
223
+ # Structures containing only one model may omit MODEL record
224
+ # In these cases model starting index is set to 0
225
+ if len(model_start_i) == 0:
226
+ model_start_i = np.array([0])
227
+
228
+ if model is None:
229
+ depth = len(model_start_i)
230
+ length = self._get_model_length(model_start_i, atom_line_i)
231
+ array = AtomArrayStack(depth, length)
232
+ # Line indices for annotation determination
233
+ # Annotation is determined from model 1,
234
+ # therefore from ATOM records before second MODEL record
235
+ if len(model_start_i) == 1:
236
+ annot_i = atom_line_i
237
+ else:
238
+ annot_i = atom_line_i[atom_line_i < model_start_i[1]]
239
+ # Line indices for coordinate determination
240
+ coord_i = atom_line_i
241
+
242
+ else:
243
+ last_model = len(model_start_i)
244
+ if model == 0:
245
+ raise ValueError("The model index must not be 0")
246
+ # Negative models mean index starting from last model
247
+ model = last_model + model + 1 if model < 0 else model
248
+
249
+ if model < last_model:
250
+ line_filter = (atom_line_i >= model_start_i[model - 1]) & (
251
+ atom_line_i < model_start_i[model]
252
+ )
253
+ elif model == last_model:
254
+ line_filter = atom_line_i >= model_start_i[model - 1]
255
+ else:
256
+ raise ValueError(
257
+ f"The file has {last_model} models, "
258
+ f"the given model {model} does not exist"
259
+ )
260
+ annot_i = coord_i = atom_line_i[line_filter]
261
+ array = AtomArray(len(coord_i))
262
+
263
+ # Save atom IDs for later sorting into the original atom order
264
+ atom_id = np.zeros(array.array_length(), int)
265
+
266
+ # Create annotation arrays
267
+ chain_id = np.zeros(array.array_length(), array.chain_id.dtype)
268
+ res_id = np.zeros(array.array_length(), array.res_id.dtype)
269
+ ins_code = np.zeros(array.array_length(), array.ins_code.dtype)
270
+ res_name = np.zeros(array.array_length(), array.res_name.dtype)
271
+ hetero = np.zeros(array.array_length(), array.hetero.dtype)
272
+ atom_name = np.zeros(array.array_length(), array.atom_name.dtype)
273
+ element = np.zeros(array.array_length(), array.element.dtype)
274
+
275
+ # Fill annotation array
276
+ # i is index in array, line_i is line index
277
+ for i, line_i in enumerate(annot_i):
278
+ line = self.lines[line_i]
279
+
280
+ atom_id[i] = int(line[6:11])
281
+ chain_id[i] = line[21].strip()
282
+ res_id[i] = int(line[22:26])
283
+ ins_code[i] = line[26].strip()
284
+ res_name[i] = line[17:20].strip()
285
+ hetero[i] = False if line[0:4] == "ATOM" else True
286
+ atom_name[i] = line[12:16].strip()
287
+ element[i] = line[76:78].strip()
288
+
289
+ # Add annotation arrays to atom array (stack)
290
+ array.chain_id = chain_id
291
+ array.res_id = res_id
292
+ array.ins_code = ins_code
293
+ array.res_name = res_name
294
+ array.hetero = hetero
295
+ array.atom_name = atom_name
296
+ array.element = element
297
+
298
+ # Fill in coordinates
299
+ if isinstance(array, AtomArray):
300
+ for i, line_i in enumerate(coord_i):
301
+ line = self.lines[line_i]
302
+ array.coord[i, 0] = float(line[30:38])
303
+ array.coord[i, 1] = float(line[38:46])
304
+ array.coord[i, 2] = float(line[46:54])
305
+
306
+ elif isinstance(array, AtomArrayStack):
307
+ m = 0
308
+ i = 0
309
+ for line_i in atom_line_i:
310
+ if m < len(model_start_i) - 1 and line_i > model_start_i[m + 1]:
311
+ m += 1
312
+ i = 0
313
+ line = self.lines[line_i]
314
+ array.coord[m, i, 0] = float(line[30:38])
315
+ array.coord[m, i, 1] = float(line[38:46])
316
+ array.coord[m, i, 2] = float(line[46:54])
317
+ i += 1
318
+
319
+ # Sort into the original atom order
320
+ array = array[..., np.argsort(atom_id)]
321
+
322
+ return array
323
+
324
+ def set_structure(
325
+ self,
326
+ atoms,
327
+ charges=None,
328
+ atom_types=None,
329
+ rotatable_bonds=None,
330
+ root=None,
331
+ include_torsdof=True,
332
+ ):
333
+ """
334
+ Write an :class:`AtomArray` into the PDBQT file.
335
+
336
+ Parameters
337
+ ----------
338
+ atoms : AtomArray, shape=(n,)
339
+ The atoms to be written into this file.
340
+ Must have an associated :class:`BondList`.
341
+ charges : ndarray, shape=(n,), dtype=float, optional
342
+ Partial charges for each atom in `atoms`.
343
+ By default, the charges are calculated using the PEOE method
344
+ (:func:`partial_charges()`).
345
+ atom_types : ndarray, shape=(n,), dtype="U1", optional
346
+ Custom *AutoDock* atom types for each atom in `atoms`.
347
+ rotatable_bonds : None or 'rigid' or 'all' or BondList, optional
348
+ This parameter describes, how rotatable bonds are handled,
349
+ with respect to ``ROOT``, ``BRANCH`` and ``ENDBRANCH``
350
+ lines.
351
+
352
+ - ``None`` - The molecule is handled as rigid receptor:
353
+ No ``ROOT``, ``BRANCH`` and ``ENDBRANCH`` lines will
354
+ be written.
355
+ - ``'rigid'`` - The molecule is handled as rigid ligand:
356
+ Only a ``ROOT`` line will be written.
357
+ - ``'all'`` - The molecule is handled as flexible
358
+ ligand:
359
+ A ``ROOT`` line will be written and all rotatable
360
+ bonds are included using ``BRANCH`` and ``ENDBRANCH``
361
+ lines.
362
+ - :class:`BondList` - The molecule is handled as
363
+ flexible ligand:
364
+ A ``ROOT`` line will be written and all bonds in the
365
+ given :class:`BondList` are considered flexible via
366
+ ``BRANCH`` and ``ENDBRANCH`` lines.
367
+
368
+ root : int, optional
369
+ Specifies the index of the atom following the ``ROOT`` line.
370
+ Setting the root atom is useful for specifying the *anchor*
371
+ in flexible side chains.
372
+ This parameter has no effect, if `rotatable_bonds` is
373
+ ``None``.
374
+ By default, the first atom is also the root atom.
375
+ include_torsdof : bool, optional
376
+ By default, a ``TORSDOF`` (torsional degrees of freedom)
377
+ record is written at the end of the file.
378
+ By setting this parameter to false, the record is omitted.
379
+
380
+ Returns
381
+ -------
382
+ mask : ndarray, shape=(n,), dtype=bool
383
+ A boolean mask, that is ``False`` for each atom of the input
384
+ ``atoms``, that was removed due to being a nonpolar
385
+ hydrogen.
386
+ """
387
+ # Check if AtomArray is suitable for PDBQT
388
+ max_atoms, max_residues = 99999, 9999
389
+ if atoms.array_length() > max_atoms:
390
+ warnings.warn(f"More then {max_atoms:,} atoms per model")
391
+ if (atoms.res_id > max_residues).any():
392
+ warnings.warn(f"Residue IDs exceed {max_residues:,}")
393
+ if np.isnan(atoms.coord).any():
394
+ raise BadStructureError("Coordinates contain 'NaN' values")
395
+ if any([len(name) > 1 for name in atoms.chain_id]):
396
+ raise BadStructureError("Some chain IDs exceed 1 character")
397
+ if any([len(name) > 3 for name in atoms.res_name]):
398
+ raise BadStructureError("Some residue names exceed 3 characters")
399
+ if any([len(name) > 4 for name in atoms.atom_name]):
400
+ raise BadStructureError("Some atom names exceed 4 characters")
401
+
402
+ if charges is None:
403
+ charges = partial_charges(atoms)
404
+ charges[np.isnan(charges)] = 0
405
+ else:
406
+ if np.isnan(charges).any():
407
+ raise ValueError("Input charges contain NaN values")
408
+
409
+ # Get AutoDock atom types and remove nonpolar hydrogen atoms
410
+ atoms, charges, types, mask = convert_atoms(atoms, charges)
411
+ # Overwrite calculated atom types with input atom types
412
+ if atom_types is not None:
413
+ types = atom_types[mask]
414
+
415
+ if rotatable_bonds is None:
416
+ # No rotatable bonds -> the BondList contains no bonds
417
+ rotatable_bonds = BondList(atoms.bonds.get_atom_count())
418
+ use_root = False
419
+ elif rotatable_bonds == "rigid":
420
+ rotatable_bonds = BondList(atoms.bonds.get_atom_count())
421
+ use_root = True
422
+ elif rotatable_bonds == "all":
423
+ rotatable_bonds = find_rotatable_bonds(atoms.bonds)
424
+ use_root = True
425
+ else:
426
+ if rotatable_bonds.ndim != 2 or rotatable_bonds.shape[1] != 2:
427
+ raise ValueError("An (nx2) array is expected for rotatable bonds")
428
+ rotatable_bonds = BondList(len(mask), np.asarray(rotatable_bonds))[mask]
429
+ use_root = True
430
+
431
+ if root is None:
432
+ root_index = 0
433
+ else:
434
+ # Find new index of root atom, since the index might have
435
+ # been shifted due to removed atoms
436
+ original_indices = np.arange(len(mask))
437
+ new_indices = original_indices[mask]
438
+ try:
439
+ root_index = np.where(new_indices == root)[0][0]
440
+ except IndexError:
441
+ raise ValueError(
442
+ "The given root atom index points to an nonpolar hydrogen "
443
+ "atom, that has been removed"
444
+ )
445
+ # Add bonds of the rigid root to rotatable bonds,
446
+ # as they probably have been filtered out,
447
+ # as the root is probably a terminal atom
448
+ for atom, bond_type in zip(*atoms.bonds.get_bonds(root_index)):
449
+ rotatable_bonds.add_bond(root_index, atom, bond_type)
450
+
451
+ # Break rotatable bonds
452
+ # for simple branch determination in '_write_atoms()'
453
+ atoms.bonds.remove_bonds(rotatable_bonds)
454
+
455
+ hetero = ["HETATM" if e else "ATOM" for e in atoms.hetero]
456
+ if "atom_id" in atoms.get_annotation_categories():
457
+ atom_id = atoms.atom_id
458
+ else:
459
+ atom_id = np.arange(1, atoms.array_length() + 1)
460
+ occupancy = np.ones(atoms.array_length())
461
+ b_factor = np.zeros(atoms.array_length())
462
+
463
+ # Convert rotatable bonds into array for easier handling
464
+ # The bond type is irrelevant from this point on
465
+ rotatable_bonds = rotatable_bonds.as_array()[:, :2]
466
+
467
+ self.lines = []
468
+ self._write_atoms(
469
+ atoms,
470
+ charges,
471
+ types,
472
+ atom_id,
473
+ hetero,
474
+ occupancy,
475
+ b_factor,
476
+ root_index,
477
+ rotatable_bonds,
478
+ np.zeros(len(rotatable_bonds), dtype=bool),
479
+ use_root,
480
+ )
481
+ if include_torsdof:
482
+ self.lines.append(f"TORSDOF {len(rotatable_bonds)}")
483
+
484
+ return mask
485
+
486
+ def _write_atoms(
487
+ self,
488
+ atoms,
489
+ charges,
490
+ types,
491
+ atom_id,
492
+ hetero,
493
+ occupancy,
494
+ b_factor,
495
+ root_atom,
496
+ rotatable_bonds,
497
+ visited_rotatable_bonds,
498
+ is_root,
499
+ ):
500
+ if len(rotatable_bonds) != 0:
501
+ # Get the indices to atoms of this branch, i.e. a group of
502
+ # atoms that are connected by non-rotatable bonds
503
+ # Use 'find_connected()', since rotatable bonds were removed
504
+ # from the BondList before
505
+ this_branch_indices = find_connected(atoms.bonds, root_atom)
506
+ # The root atom of the branch, i.e. the atom connected by
507
+ # the rotatable bond should always be listed first
508
+ # -> Remove root atom and insert it at the beginning
509
+ this_branch_indices = np.insert(
510
+ this_branch_indices[this_branch_indices != root_atom], 0, root_atom
511
+ )
512
+ else:
513
+ # No rotatable bonds
514
+ # -> all atom are in root i.e. this branch
515
+ this_branch_indices = np.arange(atoms.array_length())
516
+
517
+ if is_root:
518
+ self.lines.append("ROOT")
519
+ for i in this_branch_indices:
520
+ self.lines.append(
521
+ f"{hetero[i]:6}"
522
+ f"{atom_id[i]:>5d} "
523
+ f"{atoms.atom_name[i]:4} "
524
+ f"{atoms.res_name[i]:3} "
525
+ f"{atoms.chain_id[i]:1}"
526
+ f"{atoms.res_id[i]:>4d}"
527
+ f"{atoms.ins_code[i]:1} "
528
+ f"{atoms.coord[i, 0]:>8.3f}"
529
+ f"{atoms.coord[i, 1]:>8.3f}"
530
+ f"{atoms.coord[i, 2]:>8.3f}"
531
+ f"{occupancy[i]:>6.2f}"
532
+ f"{b_factor[i]:>6.2f} "
533
+ f"{charges[i]:>6.3f} "
534
+ f"{types[i]:2}"
535
+ )
536
+ if is_root:
537
+ self.lines.append("ENDROOT")
538
+
539
+ if len(rotatable_bonds) == 0:
540
+ # No rotatable bonds -> no branching
541
+ return
542
+
543
+ for k, (i, j) in enumerate(rotatable_bonds):
544
+ if visited_rotatable_bonds[k]:
545
+ continue
546
+
547
+ # Create a new branch for each rotatable bond,
548
+ # that connects to an atom of this branch
549
+ if i in this_branch_indices:
550
+ this_br_i = i
551
+ new_br_i = j
552
+ elif j in this_branch_indices:
553
+ this_br_i = j
554
+ new_br_i = i
555
+ else:
556
+ # Rotatable bond does not start from this branch
557
+ continue
558
+
559
+ # Mark rotatable bond as visited as otherwise branches would
560
+ # be created back and forth over the same rotatable bond and
561
+ # this method would never terminate
562
+ visited_rotatable_bonds[k] = True
563
+
564
+ self.lines.append(
565
+ f"BRANCH {atom_id[this_br_i]:>3d} {atom_id[new_br_i]:>3d}"
566
+ )
567
+ self._write_atoms(
568
+ atoms,
569
+ charges,
570
+ types,
571
+ atom_id,
572
+ hetero,
573
+ occupancy,
574
+ b_factor,
575
+ # The root atom of the branch
576
+ # is the other atom of the rotatable bond
577
+ new_br_i,
578
+ rotatable_bonds,
579
+ visited_rotatable_bonds,
580
+ False,
581
+ )
582
+ self.lines.append(
583
+ f"ENDBRANCH {atom_id[this_br_i]:>3d} {atom_id[new_br_i]:>3d}"
584
+ )
585
+
586
+ def _get_model_length(self, model_start_i, atom_line_i):
587
+ """
588
+ Determine length of models and check that all models
589
+ have equal length.
590
+ """
591
+ n_models = len(model_start_i)
592
+ length = None
593
+ for model_i in range(len(model_start_i)):
594
+ model_start = model_start_i[model_i]
595
+ model_stop = (
596
+ model_start_i[model_i + 1]
597
+ if model_i + 1 < n_models
598
+ else len(self.lines)
599
+ )
600
+ model_length = np.count_nonzero(
601
+ (atom_line_i >= model_start) & (atom_line_i < model_stop)
602
+ )
603
+ if length is None:
604
+ length = model_length
605
+ if model_length != length:
606
+ raise InvalidFileError(
607
+ f"Model {model_i + 1} has {model_length} atoms, "
608
+ f"but model 1 has {length} atoms, must be equal"
609
+ )
610
+ return length
611
+
612
+
613
+ def convert_atoms(atoms, charges):
614
+ """
615
+ Convert atoms into *AutoDock* compatible atoms.
616
+
617
+ Parameters
618
+ ----------
619
+ atoms : AtomArray
620
+ The atoms to be converted.
621
+ charges : ndarray, dtype=float
622
+ Partial charges for the atoms.
623
+
624
+ Returns
625
+ -------
626
+ converted_atoms : AtomArray
627
+ The input `atoms`, but with deleted nonpolar hydrogen atoms.
628
+ charges : ndarray, dtype=float
629
+ The input `charges`, but with deleted entries for nonpolar
630
+ hydrogen atoms.
631
+ atom_types : ndarray, dtype="U1"
632
+ The *AutoDock* atom types.
633
+ mask : ndarray, shape=(n,), dtype=bool
634
+ A boolean mask, that is ``False`` for each atom of the input
635
+ ``atoms``, that was removed due to being a nonpolar hydrogen.
636
+ """
637
+ charges = charges.copy()
638
+ all_bonds, all_bond_types = atoms.bonds.get_all_bonds()
639
+
640
+ atom_types = np.zeros(atoms.array_length(), dtype="U2")
641
+ hydrogen_removal_mask = np.zeros(atoms.array_length(), dtype=bool)
642
+ for i in range(atoms.array_length()):
643
+ element = atoms.element[i]
644
+ bonded_atoms = all_bonds[i][all_bonds[i] != -1]
645
+ if element == "H":
646
+ if len(bonded_atoms) == 0:
647
+ # Free proton
648
+ atom_types[i] = "H"
649
+ elif len(bonded_atoms) == 1:
650
+ j = bonded_atoms[0]
651
+ bonded_element = atoms.element[j]
652
+ if bonded_element == "C":
653
+ # Remove hydrogen and add its charge
654
+ # to charge of bonded carbon
655
+ charges[j] += charges[i]
656
+ hydrogen_removal_mask[i] = True
657
+ else:
658
+ atom_types[i] = "HD"
659
+ else:
660
+ raise BadStructureError(
661
+ "Structure contains hydrogen with multiple bonds"
662
+ )
663
+ elif element == "C":
664
+ if np.isin(
665
+ all_bond_types[i], [BondType.AROMATIC_SINGLE, BondType.AROMATIC_DOUBLE]
666
+ ).any():
667
+ # Aromatic carbon
668
+ atom_types[i] = "A"
669
+ else:
670
+ # Alphatic carbon
671
+ atom_types[i] = "C"
672
+ elif element == "N":
673
+ atom_types[i] = "NA"
674
+ elif element == "O":
675
+ atom_types[i] = "OA"
676
+ elif element == "S":
677
+ atom_types[i] = "SA"
678
+ elif element.capitalize() in PARAMETRIZED_ELEMENTS:
679
+ atom_types[i] = element.capitalize()
680
+ else:
681
+ warnings.warn(
682
+ f"Element {element} is not paramtrized, "
683
+ f"using parameters for hydrogen instead"
684
+ )
685
+ atom_types[i] = "H"
686
+
687
+ mask = ~hydrogen_removal_mask
688
+ return atoms[mask], charges[mask], atom_types[mask], mask