molSimplify 1.7.4__py3-none-any.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.
Files changed (651) hide show
  1. docs/source/conf.py +224 -0
  2. molSimplify/Classes/__init__.py +6 -0
  3. molSimplify/Classes/atom3D.py +235 -0
  4. molSimplify/Classes/dft_obs.py +130 -0
  5. molSimplify/Classes/globalvars.py +827 -0
  6. molSimplify/Classes/helpers.py +161 -0
  7. molSimplify/Classes/ligand.py +2330 -0
  8. molSimplify/Classes/mGUI.py +2493 -0
  9. molSimplify/Classes/mWidgets.py +438 -0
  10. molSimplify/Classes/miniGUI.py +41 -0
  11. molSimplify/Classes/mol2D.py +260 -0
  12. molSimplify/Classes/mol3D.py +5846 -0
  13. molSimplify/Classes/monomer3D.py +253 -0
  14. molSimplify/Classes/partialcharges.py +226 -0
  15. molSimplify/Classes/protein3D.py +1178 -0
  16. molSimplify/Classes/rundiag.py +151 -0
  17. molSimplify/Data/ML.dat +212 -0
  18. molSimplify/Data/MLS_FSR_for_inter.dat +23 -0
  19. molSimplify/Data/MLS_FSR_for_inter2.dat +23 -0
  20. molSimplify/Data/MLS_angle_for_click.dat +8 -0
  21. molSimplify/Data/MLS_angle_for_inter.dat +23 -0
  22. molSimplify/Data/MLS_angle_for_inter2.dat +48 -0
  23. molSimplify/Data/MLS_angle_for_intra.dat +10 -0
  24. molSimplify/Data/MLS_angle_for_intra2.dat +6 -0
  25. molSimplify/Data/MLS_angle_for_oa.dat +18 -0
  26. molSimplify/Data/ML_FSR_for_inter.dat +112 -0
  27. molSimplify/Data/ML_FSR_for_inter2.dat +110 -0
  28. molSimplify/Data/ML_bond_for_cat.dat +8 -0
  29. molSimplify/Data/ML_bond_for_click.dat +8 -0
  30. molSimplify/Data/ML_bond_for_inter.dat +48 -0
  31. molSimplify/Data/ML_bond_for_inter2.dat +48 -0
  32. molSimplify/Data/ML_bond_for_intra.dat +10 -0
  33. molSimplify/Data/ML_bond_for_intra2.dat +6 -0
  34. molSimplify/Data/ML_bond_for_oa.dat +18 -0
  35. molSimplify/Data/bp1.dat +21 -0
  36. molSimplify/Data/li.dat +3 -0
  37. molSimplify/Data/no.dat +2 -0
  38. molSimplify/Data/oct.dat +7 -0
  39. molSimplify/Data/pbp.dat +8 -0
  40. molSimplify/Data/spy.dat +6 -0
  41. molSimplify/Data/sqap.dat +9 -0
  42. molSimplify/Data/sqp.dat +5 -0
  43. molSimplify/Data/tbp.dat +6 -0
  44. molSimplify/Data/tdhd.dat +9 -0
  45. molSimplify/Data/thd.dat +5 -0
  46. molSimplify/Data/tpl.dat +4 -0
  47. molSimplify/Data/tpr.dat +7 -0
  48. molSimplify/Informatics/HFXsensitivity/__init__.py +0 -0
  49. molSimplify/Informatics/HFXsensitivity/measure_HFX_sensitivity_oxo_hat_reb_rel.py +443 -0
  50. molSimplify/Informatics/HFXsensitivity/measure_HFX_stable.py +346 -0
  51. molSimplify/Informatics/MOF/Linker_rotation.py +179 -0
  52. molSimplify/Informatics/MOF/MOF_descriptors.py +1299 -0
  53. molSimplify/Informatics/MOF/MOF_descriptors_alternate_functional.py +589 -0
  54. molSimplify/Informatics/MOF/MOF_functionalizer.py +1648 -0
  55. molSimplify/Informatics/MOF/PBC_functions.py +1347 -0
  56. molSimplify/Informatics/MOF/__init__.py +0 -0
  57. molSimplify/Informatics/MOF/atomic.py +267 -0
  58. molSimplify/Informatics/MOF/cluster_extraction.py +388 -0
  59. molSimplify/Informatics/MOF/fragment_MOFs_for_pormake.py +895 -0
  60. molSimplify/Informatics/MOF/monofunctionalized_BDC/index_information.py +10 -0
  61. molSimplify/Informatics/Mol2Parser.py +46 -0
  62. molSimplify/Informatics/RACassemble.py +408 -0
  63. molSimplify/Informatics/__init__.py +0 -0
  64. molSimplify/Informatics/active_learning/__init__.py +0 -0
  65. molSimplify/Informatics/active_learning/expected_improvement.py +269 -0
  66. molSimplify/Informatics/autocorrelation.py +1930 -0
  67. molSimplify/Informatics/clean_autocorrelation.py +778 -0
  68. molSimplify/Informatics/coulomb_analyze.py +67 -0
  69. molSimplify/Informatics/decoration_manager.py +193 -0
  70. molSimplify/Informatics/geo_analyze.py +88 -0
  71. molSimplify/Informatics/geometrics.py +56 -0
  72. molSimplify/Informatics/graph_analyze.py +163 -0
  73. molSimplify/Informatics/graph_racs.py +288 -0
  74. molSimplify/Informatics/jupyter_vis.py +172 -0
  75. molSimplify/Informatics/lacRACAssemble.py +2192 -0
  76. molSimplify/Informatics/lacRACAssemble_bisdithiolenes.py +236 -0
  77. molSimplify/Informatics/misc_descriptors.py +198 -0
  78. molSimplify/Informatics/organic_fingerprints.py +61 -0
  79. molSimplify/Informatics/partialcharges.py +345 -0
  80. molSimplify/Informatics/protein/activesite.py +53 -0
  81. molSimplify/Informatics/protein/pymol_add_hs.py +33 -0
  82. molSimplify/Informatics/rac155_geo.py +48 -0
  83. molSimplify/Ligands/(1_methylbenzimidazol_2_yl)pyridine.xyz +45 -0
  84. molSimplify/Ligands/1-4-dimethyl-1-2-3-triazole.xyz +15 -0
  85. molSimplify/Ligands/12crown4.mol +62 -0
  86. molSimplify/Ligands/Antipyrine.mol +58 -0
  87. molSimplify/Ligands/BPAbipy.mol +106 -0
  88. molSimplify/Ligands/Hpyrrole.mol +26 -0
  89. molSimplify/Ligands/N-quinolinylbutyramidate.xyz +31 -0
  90. molSimplify/Ligands/N-quinolinylmethylmethinylacetamidate.xyz +30 -0
  91. molSimplify/Ligands/NMe2_-1.xyz +11 -0
  92. molSimplify/Ligands/PCy3.mol +111 -0
  93. molSimplify/Ligands/PMe3.xyz +15 -0
  94. molSimplify/Ligands/PPh3.mol +76 -0
  95. molSimplify/Ligands/Propyphenazone.mol +77 -0
  96. molSimplify/Ligands/acac.mol +33 -0
  97. molSimplify/Ligands/acacen.mol +76 -0
  98. molSimplify/Ligands/acetate.smi +1 -0
  99. molSimplify/Ligands/acetate.xyz +9 -0
  100. molSimplify/Ligands/aceticacidbipyridine.mol +70 -0
  101. molSimplify/Ligands/acetonitrile.mol +17 -0
  102. molSimplify/Ligands/alanine.mol +30 -0
  103. molSimplify/Ligands/alphabetizer.py +21 -0
  104. molSimplify/Ligands/amine.mol +11 -0
  105. molSimplify/Ligands/ammonia.mol +12 -0
  106. molSimplify/Ligands/arginine.mol +58 -0
  107. molSimplify/Ligands/asparagine.mol +38 -0
  108. molSimplify/Ligands/aspartic_acid.mol +35 -0
  109. molSimplify/Ligands/azide.mol +11 -0
  110. molSimplify/Ligands/benzene.mol +28 -0
  111. molSimplify/Ligands/benzene_pi.mol +30 -0
  112. molSimplify/Ligands/benzenedithiol.mol +30 -0
  113. molSimplify/Ligands/benzenethiol.mol +30 -0
  114. molSimplify/Ligands/benzylisocy.mol +38 -0
  115. molSimplify/Ligands/bidiazine.mol +42 -0
  116. molSimplify/Ligands/bidiazole.mol +38 -0
  117. molSimplify/Ligands/bifuran.mol +38 -0
  118. molSimplify/Ligands/bihydrodiazine.mol +58 -0
  119. molSimplify/Ligands/bihydrodiazole.mol +46 -0
  120. molSimplify/Ligands/bihydrooxazine.mol +54 -0
  121. molSimplify/Ligands/bihydrooxazole.mol +42 -0
  122. molSimplify/Ligands/bihydrothiazine.mol +54 -0
  123. molSimplify/Ligands/bihydrothiazole.mol +42 -0
  124. molSimplify/Ligands/biimidazole.mol +38 -0
  125. molSimplify/Ligands/bioxazole.mol +34 -0
  126. molSimplify/Ligands/bipy.mol +46 -0
  127. molSimplify/Ligands/bipyrazine.xyz +20 -0
  128. molSimplify/Ligands/bipyrimidine.mol +42 -0
  129. molSimplify/Ligands/bipyrrole.mol +42 -0
  130. molSimplify/Ligands/bisnapthyridylpyridine.mol +111 -0
  131. molSimplify/Ligands/bithiazole.mol +34 -0
  132. molSimplify/Ligands/bromide.mol +7 -0
  133. molSimplify/Ligands/bromide.smi +1 -0
  134. molSimplify/Ligands/c2.mol +9 -0
  135. molSimplify/Ligands/caprolactone.mol +41 -0
  136. molSimplify/Ligands/carbonyl.mol +8 -0
  137. molSimplify/Ligands/carboxyl.mol +13 -0
  138. molSimplify/Ligands/cat.mol +30 -0
  139. molSimplify/Ligands/chloride.mol +7 -0
  140. molSimplify/Ligands/chloride.smi +1 -0
  141. molSimplify/Ligands/chloropyridine.mol +27 -0
  142. molSimplify/Ligands/co2.mol +10 -0
  143. molSimplify/Ligands/corrolazine.mol +72 -0
  144. molSimplify/Ligands/cs.mol +8 -0
  145. molSimplify/Ligands/cyanate.xyz +5 -0
  146. molSimplify/Ligands/cyanide.mol +9 -0
  147. molSimplify/Ligands/cyanoaceticporphyrin.mol +114 -0
  148. molSimplify/Ligands/cyanopyridine.mol +29 -0
  149. molSimplify/Ligands/cyclam.mol +81 -0
  150. molSimplify/Ligands/cyclen.mol +69 -0
  151. molSimplify/Ligands/cyclopentadienyl.mol +26 -0
  152. molSimplify/Ligands/cysteine.mol +32 -0
  153. molSimplify/Ligands/diaminomethyl.mol +19 -0
  154. molSimplify/Ligands/diazine.mol +25 -0
  155. molSimplify/Ligands/diazole.mol +23 -0
  156. molSimplify/Ligands/dicyanamide.mol +15 -0
  157. molSimplify/Ligands/dihydrofuran.mol +27 -0
  158. molSimplify/Ligands/dmap.xyz +35 -0
  159. molSimplify/Ligands/dmf.mol +28 -0
  160. molSimplify/Ligands/dmi.mol +41 -0
  161. molSimplify/Ligands/dmpe.mol +52 -0
  162. molSimplify/Ligands/dpmu.mol +47 -0
  163. molSimplify/Ligands/dppe.mol +112 -0
  164. molSimplify/Ligands/edta.mol +69 -0
  165. molSimplify/Ligands/en.mol +28 -0
  166. molSimplify/Ligands/ethanethiol.mol +21 -0
  167. molSimplify/Ligands/ethanolamine.mol +26 -0
  168. molSimplify/Ligands/ethbipy.mol +70 -0
  169. molSimplify/Ligands/ethyl.mol +19 -0
  170. molSimplify/Ligands/ethylamine.mol +24 -0
  171. molSimplify/Ligands/ethylene.mol +16 -0
  172. molSimplify/Ligands/ethylesteracac.mol +57 -0
  173. molSimplify/Ligands/fluoride.mol +7 -0
  174. molSimplify/Ligands/fluoride.smi +1 -0
  175. molSimplify/Ligands/formaldehyde.mol +12 -0
  176. molSimplify/Ligands/formamidate.xyz +8 -0
  177. molSimplify/Ligands/formate.xyz +6 -0
  178. molSimplify/Ligands/furan.mol +23 -0
  179. molSimplify/Ligands/glutamic_acid.mol +42 -0
  180. molSimplify/Ligands/glutamine.mol +44 -0
  181. molSimplify/Ligands/glycinate.mol +23 -0
  182. molSimplify/Ligands/glycine.mol +24 -0
  183. molSimplify/Ligands/h2s.mol +10 -0
  184. molSimplify/Ligands/helium.mol +6 -0
  185. molSimplify/Ligands/histidine.mol +45 -0
  186. molSimplify/Ligands/hmpa.mol +62 -0
  187. molSimplify/Ligands/hs-.mol +9 -0
  188. molSimplify/Ligands/hydride.mol +7 -0
  189. molSimplify/Ligands/hydrocarboxyacetylide.xyz +8 -0
  190. molSimplify/Ligands/hydrocyanide.mol +10 -0
  191. molSimplify/Ligands/hydrodiazine.mol +33 -0
  192. molSimplify/Ligands/hydrodiazole.mol +27 -0
  193. molSimplify/Ligands/hydrogensulfide.mol +10 -0
  194. molSimplify/Ligands/hydroisocyanide.mol +11 -0
  195. molSimplify/Ligands/hydrooxazine.mol +31 -0
  196. molSimplify/Ligands/hydrooxazole.mol +25 -0
  197. molSimplify/Ligands/hydrothiazine.mol +31 -0
  198. molSimplify/Ligands/hydrothiazole.mol +25 -0
  199. molSimplify/Ligands/hydroxyl.mol +9 -0
  200. molSimplify/Ligands/imidazole.mol +23 -0
  201. molSimplify/Ligands/imidazolidinone.mol +29 -0
  202. molSimplify/Ligands/imine.mol +13 -0
  203. molSimplify/Ligands/iminodiacetic.mol +33 -0
  204. molSimplify/Ligands/iodide.mol +7 -0
  205. molSimplify/Ligands/iodobenzene.xyz +14 -0
  206. molSimplify/Ligands/isoleucine.mol +48 -0
  207. molSimplify/Ligands/isothiocyanate.mol +11 -0
  208. molSimplify/Ligands/leucine.mol +48 -0
  209. molSimplify/Ligands/ligands.dict +257 -0
  210. molSimplify/Ligands/lysine.mol +54 -0
  211. molSimplify/Ligands/mebenzenedithiol.mol +36 -0
  212. molSimplify/Ligands/mebim_py.xyz +29 -0
  213. molSimplify/Ligands/mebim_pz.xyz +28 -0
  214. molSimplify/Ligands/mebipy.mol +58 -0
  215. molSimplify/Ligands/mecat.mol +36 -0
  216. molSimplify/Ligands/methanal.mol +11 -0
  217. molSimplify/Ligands/methanethiol.mol +15 -0
  218. molSimplify/Ligands/methanol.mol +16 -0
  219. molSimplify/Ligands/methionine.mol +44 -0
  220. molSimplify/Ligands/methyl.mol +13 -0
  221. molSimplify/Ligands/methylacetylide.xyz +8 -0
  222. molSimplify/Ligands/methylamine.mol +19 -0
  223. molSimplify/Ligands/methylazide.xyz +9 -0
  224. molSimplify/Ligands/methylisocy.mol +17 -0
  225. molSimplify/Ligands/methylpyridine.mol +33 -0
  226. molSimplify/Ligands/n2.mol +8 -0
  227. molSimplify/Ligands/n4py.xyz +51 -0
  228. molSimplify/Ligands/nch.mol +10 -0
  229. molSimplify/Ligands/nco-.mol +11 -0
  230. molSimplify/Ligands/nethanolamine.mol +26 -0
  231. molSimplify/Ligands/nitrate.mol +14 -0
  232. molSimplify/Ligands/nitrite.mol +11 -0
  233. molSimplify/Ligands/nitro.mol +11 -0
  234. molSimplify/Ligands/nitrobipy.mol +54 -0
  235. molSimplify/Ligands/nitroso.mol +8 -0
  236. molSimplify/Ligands/nme3.mol +30 -0
  237. molSimplify/Ligands/no-.mol +10 -0
  238. molSimplify/Ligands/no2-.mol +11 -0
  239. molSimplify/Ligands/noxygen.mol +8 -0
  240. molSimplify/Ligands/ns-.mol +10 -0
  241. molSimplify/Ligands/o-pyridylbenzene.xyz +23 -0
  242. molSimplify/Ligands/o-pyridylphenylanion.xyz +22 -0
  243. molSimplify/Ligands/o2-.mol +9 -0
  244. molSimplify/Ligands/o2.xyz +4 -0
  245. molSimplify/Ligands/och2.mol +12 -0
  246. molSimplify/Ligands/oethanolamine.mol +26 -0
  247. molSimplify/Ligands/ome2.mol +22 -0
  248. molSimplify/Ligands/ooh.xyz +5 -0
  249. molSimplify/Ligands/oxalate.mol +17 -0
  250. molSimplify/Ligands/oxalate.smi +1 -0
  251. molSimplify/Ligands/oxygen.mol +7 -0
  252. molSimplify/Ligands/pentacyanocyclopentadienide.mol +36 -0
  253. molSimplify/Ligands/ph2-.mol +11 -0
  254. molSimplify/Ligands/ph3.mol +12 -0
  255. molSimplify/Ligands/phen.mol +51 -0
  256. molSimplify/Ligands/phenacac.mol +63 -0
  257. molSimplify/Ligands/phenalalanine.mol +51 -0
  258. molSimplify/Ligands/phendione.mol +51 -0
  259. molSimplify/Ligands/phenphen.mol +75 -0
  260. molSimplify/Ligands/phenylbenzoxazole.mol +54 -0
  261. molSimplify/Ligands/phenylcyc.mol +99 -0
  262. molSimplify/Ligands/phenylenediamine.mol +37 -0
  263. molSimplify/Ligands/phenylisocy.mol +32 -0
  264. molSimplify/Ligands/phosacidbipy.mol +66 -0
  265. molSimplify/Ligands/phosphine.mol +13 -0
  266. molSimplify/Ligands/phosphorine.mol +27 -0
  267. molSimplify/Ligands/phosphorustrifluoride.mol +12 -0
  268. molSimplify/Ligands/phthalocyanine.mol +126 -0
  269. molSimplify/Ligands/pme3o.mol +32 -0
  270. molSimplify/Ligands/porphyrin.mol +82 -0
  271. molSimplify/Ligands/pph3o.mol +77 -0
  272. molSimplify/Ligands/proline.mol +39 -0
  273. molSimplify/Ligands/propdiol.mol +21 -0
  274. molSimplify/Ligands/propylene.mol +23 -0
  275. molSimplify/Ligands/pyridine.mol +27 -0
  276. molSimplify/Ligands/pyrimidone.mol +27 -0
  277. molSimplify/Ligands/pyrrole.mol +24 -0
  278. molSimplify/Ligands/quinoxalinedithiol.mol +39 -0
  279. molSimplify/Ligands/s2-.mol +9 -0
  280. molSimplify/Ligands/salen.mol +75 -0
  281. molSimplify/Ligands/salphen.mol +84 -0
  282. molSimplify/Ligands/serine.mol +32 -0
  283. molSimplify/Ligands/simple_ligands.dict +14 -0
  284. molSimplify/Ligands/sulfacidbipy.mol +63 -0
  285. molSimplify/Ligands/tbucat.mol +54 -0
  286. molSimplify/Ligands/tbuphisocy.mol +56 -0
  287. molSimplify/Ligands/tbutylcyclen.mol +166 -0
  288. molSimplify/Ligands/tbutylisocy.mol +35 -0
  289. molSimplify/Ligands/tbutylthiol.mol +33 -0
  290. molSimplify/Ligands/tcnoet.mol +43 -0
  291. molSimplify/Ligands/tcnoetOH.mol +45 -0
  292. molSimplify/Ligands/terpy.mol +65 -0
  293. molSimplify/Ligands/tetrahydrofuran.mol +31 -0
  294. molSimplify/Ligands/thiane.mol +37 -0
  295. molSimplify/Ligands/thiazole.mol +21 -0
  296. molSimplify/Ligands/thiocyanate.mol +11 -0
  297. molSimplify/Ligands/thiol.mol +9 -0
  298. molSimplify/Ligands/thiophene.mol +23 -0
  299. molSimplify/Ligands/thiopyridine.mol +29 -0
  300. molSimplify/Ligands/threonine.mol +38 -0
  301. molSimplify/Ligands/tpp.mol +165 -0
  302. molSimplify/Ligands/tricyanomethyl.mol +19 -0
  303. molSimplify/Ligands/trifluoromethyl.mol +13 -0
  304. molSimplify/Ligands/tryptophan.mol +60 -0
  305. molSimplify/Ligands/tyrosine.mol +53 -0
  306. molSimplify/Ligands/uthiol.mol +11 -0
  307. molSimplify/Ligands/uthiolme2.mol +23 -0
  308. molSimplify/Ligands/valine.mol +42 -0
  309. molSimplify/Ligands/water.mol +10 -0
  310. molSimplify/Ligands/x.mol +6 -0
  311. molSimplify/Scripts/__init__.py +0 -0
  312. molSimplify/Scripts/addtodb.py +308 -0
  313. molSimplify/Scripts/cellbuilder.py +1592 -0
  314. molSimplify/Scripts/cellbuilder_tools.py +701 -0
  315. molSimplify/Scripts/chains.py +342 -0
  316. molSimplify/Scripts/convert_2to3.py +23 -0
  317. molSimplify/Scripts/dbinteract.py +631 -0
  318. molSimplify/Scripts/distgeom.py +617 -0
  319. molSimplify/Scripts/findcorrelations.py +287 -0
  320. molSimplify/Scripts/generator.py +267 -0
  321. molSimplify/Scripts/geometry.py +1224 -0
  322. molSimplify/Scripts/grabguivars.py +845 -0
  323. molSimplify/Scripts/in_b3lyp_usetc.py +141 -0
  324. molSimplify/Scripts/inparse.py +1673 -0
  325. molSimplify/Scripts/io.py +1149 -0
  326. molSimplify/Scripts/isomers.py +415 -0
  327. molSimplify/Scripts/jobgen.py +247 -0
  328. molSimplify/Scripts/krr_prep.py +1262 -0
  329. molSimplify/Scripts/molSimplify_io.py +18 -0
  330. molSimplify/Scripts/molden2psi4wfn.py +166 -0
  331. molSimplify/Scripts/namegen.py +32 -0
  332. molSimplify/Scripts/nn_prep.py +561 -0
  333. molSimplify/Scripts/oct_check_mols.py +782 -0
  334. molSimplify/Scripts/periodic_QE.py +97 -0
  335. molSimplify/Scripts/postmold.py +304 -0
  336. molSimplify/Scripts/postmwfn.py +709 -0
  337. molSimplify/Scripts/postparse.py +488 -0
  338. molSimplify/Scripts/postproc.py +139 -0
  339. molSimplify/Scripts/qcgen.py +1450 -0
  340. molSimplify/Scripts/rmsd.py +489 -0
  341. molSimplify/Scripts/rungen.py +670 -0
  342. molSimplify/Scripts/structgen.py +3040 -0
  343. molSimplify/Scripts/tf_nn_prep.py +894 -0
  344. molSimplify/Scripts/tsgen.py +295 -0
  345. molSimplify/Scripts/uq_calibration.py +69 -0
  346. molSimplify/__init__.py +0 -0
  347. molSimplify/__main__.py +197 -0
  348. molSimplify/icons/chemdb.png +0 -0
  349. molSimplify/icons/hjklogo.png +0 -0
  350. molSimplify/icons/icon.png +0 -0
  351. molSimplify/icons/logo.png +0 -0
  352. molSimplify/icons/logo_old.png +0 -0
  353. molSimplify/icons/petachem.png +0 -0
  354. molSimplify/icons/petachem2.png +0 -0
  355. molSimplify/icons/petachem_full.png +0 -0
  356. molSimplify/icons/pythonlogo.png +0 -0
  357. molSimplify/icons/sge copy.png +0 -0
  358. molSimplify/icons/sge.png +0 -0
  359. molSimplify/icons/slurm.png +0 -0
  360. molSimplify/icons/wft1.png +0 -0
  361. molSimplify/icons/wft2.png +0 -0
  362. molSimplify/icons/wft3.png +0 -0
  363. molSimplify/ml/__init__.py +0 -0
  364. molSimplify/ml/kernels.py +36 -0
  365. molSimplify/ml/layers.py +29 -0
  366. molSimplify/molscontrol/__init__.py +14 -0
  367. molSimplify/molscontrol/_version.py +521 -0
  368. molSimplify/molscontrol/clf_tools.py +144 -0
  369. molSimplify/molscontrol/data/README.md +21 -0
  370. molSimplify/molscontrol/data/look_and_say.dat +15 -0
  371. molSimplify/molscontrol/dynamic_classifier.py +514 -0
  372. molSimplify/molscontrol/io_tools.py +363 -0
  373. molSimplify/molscontrol/molscontrol.py +49 -0
  374. molSimplify/molscontrol/terachem/jobscript_control.sh +31 -0
  375. molSimplify/molscontrol/terachem/terachem_input +22 -0
  376. molSimplify/python_krr/X_train_TS.csv +535 -0
  377. molSimplify/python_krr/__init__.py +0 -0
  378. molSimplify/python_krr/hat2_X_mean_std.csv +3 -0
  379. molSimplify/python_krr/hat2_feature_names.csv +1 -0
  380. molSimplify/python_krr/hat2_y_mean_std.csv +2 -0
  381. molSimplify/python_krr/hat_X_mean_std.csv +6 -0
  382. molSimplify/python_krr/hat_feature_names.csv +1 -0
  383. molSimplify/python_krr/hat_krr_X_train.csv +5205 -0
  384. molSimplify/python_krr/hat_krr_dual_coef.csv +1 -0
  385. molSimplify/python_krr/hat_y_mean_std.csv +2 -0
  386. molSimplify/python_krr/sklearn_models.py +34 -0
  387. molSimplify/python_krr/y_train_TS.csv +535 -0
  388. molSimplify/python_nn/ANN.py +198 -0
  389. molSimplify/python_nn/__init__.py +0 -0
  390. molSimplify/python_nn/clf_analysis_tool.py +125 -0
  391. molSimplify/python_nn/dictionary_toolbox.py +49 -0
  392. molSimplify/python_nn/ensemble_test.py +309 -0
  393. molSimplify/python_nn/hs_center.csv +26 -0
  394. molSimplify/python_nn/hs_scale.csv +26 -0
  395. molSimplify/python_nn/ls_center.csv +26 -0
  396. molSimplify/python_nn/ls_scale.csv +26 -0
  397. molSimplify/python_nn/ms_hs_b1.csv +50 -0
  398. molSimplify/python_nn/ms_hs_b2.csv +50 -0
  399. molSimplify/python_nn/ms_hs_b3.csv +1 -0
  400. molSimplify/python_nn/ms_hs_w1.csv +50 -0
  401. molSimplify/python_nn/ms_hs_w2.csv +50 -0
  402. molSimplify/python_nn/ms_hs_w3.csv +1 -0
  403. molSimplify/python_nn/ms_ls_b1.csv +50 -0
  404. molSimplify/python_nn/ms_ls_b2.csv +50 -0
  405. molSimplify/python_nn/ms_ls_b3.csv +1 -0
  406. molSimplify/python_nn/ms_ls_w1.csv +50 -0
  407. molSimplify/python_nn/ms_ls_w2.csv +50 -0
  408. molSimplify/python_nn/ms_ls_w3.csv +1 -0
  409. molSimplify/python_nn/ms_slope_b1.csv +50 -0
  410. molSimplify/python_nn/ms_slope_b2.csv +50 -0
  411. molSimplify/python_nn/ms_slope_b3.csv +1 -0
  412. molSimplify/python_nn/ms_slope_w1.csv +50 -0
  413. molSimplify/python_nn/ms_slope_w2.csv +50 -0
  414. molSimplify/python_nn/ms_slope_w3.csv +1 -0
  415. molSimplify/python_nn/ms_split_b1.csv +50 -0
  416. molSimplify/python_nn/ms_split_b2.csv +50 -0
  417. molSimplify/python_nn/ms_split_b3.csv +1 -0
  418. molSimplify/python_nn/ms_split_w1.csv +50 -0
  419. molSimplify/python_nn/ms_split_w2.csv +50 -0
  420. molSimplify/python_nn/ms_split_w3.csv +1 -0
  421. molSimplify/python_nn/slope_center.csv +25 -0
  422. molSimplify/python_nn/slope_scale.csv +25 -0
  423. molSimplify/python_nn/split_center.csv +26 -0
  424. molSimplify/python_nn/split_scale.csv +26 -0
  425. molSimplify/python_nn/tf_ANN.py +762 -0
  426. molSimplify/python_nn/train_data.csv +1211 -0
  427. molSimplify/tf_nn/__init__.py +0 -0
  428. molSimplify/tf_nn/geo_static_clf/geo_static_clf_model.h5 +0 -0
  429. molSimplify/tf_nn/geo_static_clf/geo_static_clf_train_name.csv +1591 -0
  430. molSimplify/tf_nn/geo_static_clf/geo_static_clf_train_x.csv +2790 -0
  431. molSimplify/tf_nn/geo_static_clf/geo_static_clf_train_y.csv +2790 -0
  432. molSimplify/tf_nn/geo_static_clf/geo_static_clf_vars.csv +154 -0
  433. molSimplify/tf_nn/geos/hs_ii_bl_x.csv +1577 -0
  434. molSimplify/tf_nn/geos/hs_ii_bl_y.csv +1577 -0
  435. molSimplify/tf_nn/geos/hs_ii_model.h5 +0 -0
  436. molSimplify/tf_nn/geos/hs_ii_model.json +1 -0
  437. molSimplify/tf_nn/geos/hs_ii_vars.csv +154 -0
  438. molSimplify/tf_nn/geos/hs_iii_bl_x.csv +1659 -0
  439. molSimplify/tf_nn/geos/hs_iii_bl_y.csv +1659 -0
  440. molSimplify/tf_nn/geos/hs_iii_model.h5 +0 -0
  441. molSimplify/tf_nn/geos/hs_iii_model.json +1 -0
  442. molSimplify/tf_nn/geos/hs_iii_vars.csv +154 -0
  443. molSimplify/tf_nn/geos/ls_ii_bl_x.csv +1374 -0
  444. molSimplify/tf_nn/geos/ls_ii_bl_y.csv +1374 -0
  445. molSimplify/tf_nn/geos/ls_ii_model.h5 +0 -0
  446. molSimplify/tf_nn/geos/ls_ii_model.json +1 -0
  447. molSimplify/tf_nn/geos/ls_ii_vars.csv +154 -0
  448. molSimplify/tf_nn/geos/ls_iii_bl_x.csv +1364 -0
  449. molSimplify/tf_nn/geos/ls_iii_bl_y.csv +1364 -0
  450. molSimplify/tf_nn/geos/ls_iii_model.h5 +0 -0
  451. molSimplify/tf_nn/geos/ls_iii_model.json +1 -0
  452. molSimplify/tf_nn/geos/ls_iii_vars.csv +154 -0
  453. molSimplify/tf_nn/homolumo/gap_model.h5 +0 -0
  454. molSimplify/tf_nn/homolumo/gap_model.json +1 -0
  455. molSimplify/tf_nn/homolumo/gap_test_names.csv +175 -0
  456. molSimplify/tf_nn/homolumo/gap_test_x.csv +176 -0
  457. molSimplify/tf_nn/homolumo/gap_test_y.csv +176 -0
  458. molSimplify/tf_nn/homolumo/gap_train_names.csv +699 -0
  459. molSimplify/tf_nn/homolumo/gap_train_x.csv +700 -0
  460. molSimplify/tf_nn/homolumo/gap_train_y.csv +700 -0
  461. molSimplify/tf_nn/homolumo/gap_vars.csv +153 -0
  462. molSimplify/tf_nn/homolumo/homo_model.h5 +0 -0
  463. molSimplify/tf_nn/homolumo/homo_model.json +126 -0
  464. molSimplify/tf_nn/homolumo/homo_test_names.csv +175 -0
  465. molSimplify/tf_nn/homolumo/homo_test_x.csv +176 -0
  466. molSimplify/tf_nn/homolumo/homo_test_y.csv +176 -0
  467. molSimplify/tf_nn/homolumo/homo_train_names.csv +699 -0
  468. molSimplify/tf_nn/homolumo/homo_train_x.csv +700 -0
  469. molSimplify/tf_nn/homolumo/homo_train_y.csv +700 -0
  470. molSimplify/tf_nn/homolumo/homo_vars.csv +153 -0
  471. molSimplify/tf_nn/oxoandhomo/homo_empty_info.json +7 -0
  472. molSimplify/tf_nn/oxoandhomo/homo_empty_model.h5 +0 -0
  473. molSimplify/tf_nn/oxoandhomo/homo_empty_model.json +1 -0
  474. molSimplify/tf_nn/oxoandhomo/homo_empty_test_names.csv +143 -0
  475. molSimplify/tf_nn/oxoandhomo/homo_empty_test_x.csv +144 -0
  476. molSimplify/tf_nn/oxoandhomo/homo_empty_test_y.csv +144 -0
  477. molSimplify/tf_nn/oxoandhomo/homo_empty_train_names.csv +513 -0
  478. molSimplify/tf_nn/oxoandhomo/homo_empty_train_x.csv +514 -0
  479. molSimplify/tf_nn/oxoandhomo/homo_empty_train_y.csv +514 -0
  480. molSimplify/tf_nn/oxoandhomo/homo_empty_val_names.csv +143 -0
  481. molSimplify/tf_nn/oxoandhomo/homo_empty_val_x.csv +58 -0
  482. molSimplify/tf_nn/oxoandhomo/homo_empty_val_y.csv +58 -0
  483. molSimplify/tf_nn/oxoandhomo/homo_empty_vars.csv +155 -0
  484. molSimplify/tf_nn/oxoandhomo/oxo20_info.json +7 -0
  485. molSimplify/tf_nn/oxoandhomo/oxo20_model.h5 +0 -0
  486. molSimplify/tf_nn/oxoandhomo/oxo20_model.json +1 -0
  487. molSimplify/tf_nn/oxoandhomo/oxo20_test_names.csv +143 -0
  488. molSimplify/tf_nn/oxoandhomo/oxo20_test_x.csv +144 -0
  489. molSimplify/tf_nn/oxoandhomo/oxo20_test_y.csv +144 -0
  490. molSimplify/tf_nn/oxoandhomo/oxo20_train_names.csv +513 -0
  491. molSimplify/tf_nn/oxoandhomo/oxo20_train_x.csv +514 -0
  492. molSimplify/tf_nn/oxoandhomo/oxo20_train_y.csv +514 -0
  493. molSimplify/tf_nn/oxoandhomo/oxo20_val_names.csv +143 -0
  494. molSimplify/tf_nn/oxoandhomo/oxo20_val_x.csv +58 -0
  495. molSimplify/tf_nn/oxoandhomo/oxo20_val_y.csv +58 -0
  496. molSimplify/tf_nn/oxoandhomo/oxo20_vars.csv +154 -0
  497. molSimplify/tf_nn/oxocatalysis/hat_model.h5 +0 -0
  498. molSimplify/tf_nn/oxocatalysis/hat_model.json +1 -0
  499. molSimplify/tf_nn/oxocatalysis/hat_test_names.csv +419 -0
  500. molSimplify/tf_nn/oxocatalysis/hat_test_x.csv +420 -0
  501. molSimplify/tf_nn/oxocatalysis/hat_test_y.csv +420 -0
  502. molSimplify/tf_nn/oxocatalysis/hat_train_names.csv +1507 -0
  503. molSimplify/tf_nn/oxocatalysis/hat_train_x.csv +1508 -0
  504. molSimplify/tf_nn/oxocatalysis/hat_train_y.csv +1508 -0
  505. molSimplify/tf_nn/oxocatalysis/hat_val_x.csv +169 -0
  506. molSimplify/tf_nn/oxocatalysis/hat_val_y.csv +169 -0
  507. molSimplify/tf_nn/oxocatalysis/hat_vars.csv +162 -0
  508. molSimplify/tf_nn/oxocatalysis/oxo_model.h5 +0 -0
  509. molSimplify/tf_nn/oxocatalysis/oxo_model.json +1 -0
  510. molSimplify/tf_nn/oxocatalysis/oxo_test_names.csv +527 -0
  511. molSimplify/tf_nn/oxocatalysis/oxo_test_x.csv +528 -0
  512. molSimplify/tf_nn/oxocatalysis/oxo_test_y.csv +528 -0
  513. molSimplify/tf_nn/oxocatalysis/oxo_train_names.csv +1897 -0
  514. molSimplify/tf_nn/oxocatalysis/oxo_train_x.csv +1898 -0
  515. molSimplify/tf_nn/oxocatalysis/oxo_train_y.csv +1898 -0
  516. molSimplify/tf_nn/oxocatalysis/oxo_val_x.csv +212 -0
  517. molSimplify/tf_nn/oxocatalysis/oxo_val_y.csv +212 -0
  518. molSimplify/tf_nn/oxocatalysis/oxo_vars.csv +162 -0
  519. molSimplify/tf_nn/rescaling_data/gap_mean_x.csv +153 -0
  520. molSimplify/tf_nn/rescaling_data/gap_mean_y.csv +1 -0
  521. molSimplify/tf_nn/rescaling_data/gap_var_x.csv +153 -0
  522. molSimplify/tf_nn/rescaling_data/gap_var_y.csv +1 -0
  523. molSimplify/tf_nn/rescaling_data/geo_static_clf_mean_x.csv +154 -0
  524. molSimplify/tf_nn/rescaling_data/geo_static_clf_mean_y.csv +1 -0
  525. molSimplify/tf_nn/rescaling_data/geo_static_clf_var_x.csv +154 -0
  526. molSimplify/tf_nn/rescaling_data/geo_static_clf_var_y.csv +1 -0
  527. molSimplify/tf_nn/rescaling_data/hat_mean_x.csv +162 -0
  528. molSimplify/tf_nn/rescaling_data/hat_mean_y.csv +1 -0
  529. molSimplify/tf_nn/rescaling_data/hat_var_x.csv +162 -0
  530. molSimplify/tf_nn/rescaling_data/hat_var_y.csv +1 -0
  531. molSimplify/tf_nn/rescaling_data/homo_empty_mean_x.csv +155 -0
  532. molSimplify/tf_nn/rescaling_data/homo_empty_mean_y.csv +1 -0
  533. molSimplify/tf_nn/rescaling_data/homo_empty_var_x.csv +155 -0
  534. molSimplify/tf_nn/rescaling_data/homo_empty_var_y.csv +1 -0
  535. molSimplify/tf_nn/rescaling_data/homo_mean_x.csv +153 -0
  536. molSimplify/tf_nn/rescaling_data/homo_mean_y.csv +1 -0
  537. molSimplify/tf_nn/rescaling_data/homo_var_x.csv +153 -0
  538. molSimplify/tf_nn/rescaling_data/homo_var_y.csv +1 -0
  539. molSimplify/tf_nn/rescaling_data/hs_ii_mean_x.csv +154 -0
  540. molSimplify/tf_nn/rescaling_data/hs_ii_mean_y.csv +3 -0
  541. molSimplify/tf_nn/rescaling_data/hs_ii_var_x.csv +154 -0
  542. molSimplify/tf_nn/rescaling_data/hs_ii_var_y.csv +3 -0
  543. molSimplify/tf_nn/rescaling_data/hs_iii_mean_x.csv +154 -0
  544. molSimplify/tf_nn/rescaling_data/hs_iii_mean_y.csv +3 -0
  545. molSimplify/tf_nn/rescaling_data/hs_iii_var_x.csv +154 -0
  546. molSimplify/tf_nn/rescaling_data/hs_iii_var_y.csv +3 -0
  547. molSimplify/tf_nn/rescaling_data/ls_ii_mean_x.csv +154 -0
  548. molSimplify/tf_nn/rescaling_data/ls_ii_mean_y.csv +3 -0
  549. molSimplify/tf_nn/rescaling_data/ls_ii_var_x.csv +154 -0
  550. molSimplify/tf_nn/rescaling_data/ls_ii_var_y.csv +3 -0
  551. molSimplify/tf_nn/rescaling_data/ls_iii_mean_x.csv +154 -0
  552. molSimplify/tf_nn/rescaling_data/ls_iii_mean_y.csv +3 -0
  553. molSimplify/tf_nn/rescaling_data/ls_iii_var_x.csv +154 -0
  554. molSimplify/tf_nn/rescaling_data/ls_iii_var_y.csv +3 -0
  555. molSimplify/tf_nn/rescaling_data/oxo20_mean_x.csv +154 -0
  556. molSimplify/tf_nn/rescaling_data/oxo20_mean_y.csv +1 -0
  557. molSimplify/tf_nn/rescaling_data/oxo20_var_x.csv +154 -0
  558. molSimplify/tf_nn/rescaling_data/oxo20_var_y.csv +1 -0
  559. molSimplify/tf_nn/rescaling_data/oxo_mean_x.csv +162 -0
  560. molSimplify/tf_nn/rescaling_data/oxo_mean_y.csv +1 -0
  561. molSimplify/tf_nn/rescaling_data/oxo_var_x.csv +162 -0
  562. molSimplify/tf_nn/rescaling_data/oxo_var_y.csv +1 -0
  563. molSimplify/tf_nn/rescaling_data/sc_static_clf_mean_x.csv +154 -0
  564. molSimplify/tf_nn/rescaling_data/sc_static_clf_mean_y.csv +1 -0
  565. molSimplify/tf_nn/rescaling_data/sc_static_clf_var_x.csv +154 -0
  566. molSimplify/tf_nn/rescaling_data/sc_static_clf_var_y.csv +1 -0
  567. molSimplify/tf_nn/rescaling_data/split_mean_x.csv +155 -0
  568. molSimplify/tf_nn/rescaling_data/split_mean_y.csv +1 -0
  569. molSimplify/tf_nn/rescaling_data/split_var_x.csv +155 -0
  570. molSimplify/tf_nn/rescaling_data/split_var_y.csv +1 -0
  571. molSimplify/tf_nn/sc_static_clf/sc_static_clf_model.h5 +0 -0
  572. molSimplify/tf_nn/sc_static_clf/sc_static_clf_train_name.csv +1591 -0
  573. molSimplify/tf_nn/sc_static_clf/sc_static_clf_train_x.csv +1592 -0
  574. molSimplify/tf_nn/sc_static_clf/sc_static_clf_train_y.csv +1592 -0
  575. molSimplify/tf_nn/sc_static_clf/sc_static_clf_vars.csv +154 -0
  576. molSimplify/tf_nn/split/split_model.h5 +0 -0
  577. molSimplify/tf_nn/split/split_model.json +1 -0
  578. molSimplify/tf_nn/split/split_vars.csv +155 -0
  579. molSimplify/tf_nn/split/split_x.csv +1902 -0
  580. molSimplify/tf_nn/split/split_y.csv +1902 -0
  581. molSimplify/tf_nn/split/train_names.csv +1901 -0
  582. molSimplify/utils/__init__.py +0 -0
  583. molSimplify/utils/decorators.py +16 -0
  584. molSimplify/utils/metaclasses.py +12 -0
  585. molSimplify/utils/tensorflow.py +23 -0
  586. molSimplify/utils/timer.py +16 -0
  587. molSimplify-1.7.4.dist-info/LICENSE +674 -0
  588. molSimplify-1.7.4.dist-info/METADATA +821 -0
  589. molSimplify-1.7.4.dist-info/RECORD +651 -0
  590. molSimplify-1.7.4.dist-info/WHEEL +5 -0
  591. molSimplify-1.7.4.dist-info/entry_points.txt +3 -0
  592. molSimplify-1.7.4.dist-info/top_level.txt +4 -0
  593. tests/generateTests.py +122 -0
  594. tests/helperFuncs.py +658 -0
  595. tests/informatics/test_MOF_descriptors.py +128 -0
  596. tests/informatics/test_active_learning.py +113 -0
  597. tests/informatics/test_coulomb_analyze.py +24 -0
  598. tests/informatics/test_graph_racs.py +193 -0
  599. tests/ml/test_kernels.py +20 -0
  600. tests/ml/test_layers.py +47 -0
  601. tests/runtest.py +10 -0
  602. tests/test_Mol2D.py +128 -0
  603. tests/test_basic_imports.py +62 -0
  604. tests/test_bidentate.py +25 -0
  605. tests/test_cli.py +20 -0
  606. tests/test_distgeom.py +106 -0
  607. tests/test_example_1.py +29 -0
  608. tests/test_example_3.py +31 -0
  609. tests/test_example_5.py +43 -0
  610. tests/test_example_7.py +28 -0
  611. tests/test_example_8.py +15 -0
  612. tests/test_example_tbp.py +15 -0
  613. tests/test_ff_xtb.py +111 -0
  614. tests/test_geocheck_oct.py +26 -0
  615. tests/test_geocheck_one_empty.py +15 -0
  616. tests/test_geometry.py +44 -0
  617. tests/test_inparse.py +76 -0
  618. tests/test_io.py +84 -0
  619. tests/test_jobgen.py +84 -0
  620. tests/test_joption_pythonic.py +27 -0
  621. tests/test_ligand_assign.py +58 -0
  622. tests/test_ligand_assign_consistent.py +60 -0
  623. tests/test_ligand_class.py +26 -0
  624. tests/test_ligand_from_mol_file.py +35 -0
  625. tests/test_ligands.py +86 -0
  626. tests/test_mol3D.py +337 -0
  627. tests/test_molcas_caspt2.py +15 -0
  628. tests/test_molcas_casscf.py +15 -0
  629. tests/test_old_ANNs.py +68 -0
  630. tests/test_orca_ccsdt.py +15 -0
  631. tests/test_orca_dft.py +15 -0
  632. tests/test_qcgen.py +50 -0
  633. tests/test_racs.py +124 -0
  634. tests/test_rmsd.py +68 -0
  635. tests/test_structgen_functions.py +198 -0
  636. tests/test_tetrahedral.py +29 -0
  637. tests/test_tutorial_10_part_one.py +16 -0
  638. tests/test_tutorial_10_part_two.py +15 -0
  639. tests/test_tutorial_2.py +11 -0
  640. tests/test_tutorial_3.py +15 -0
  641. tests/test_tutorial_4.py +57 -0
  642. tests/test_tutorial_6.py +10 -0
  643. tests/test_tutorial_8.py +29 -0
  644. tests/test_tutorial_9_part_one.py +15 -0
  645. tests/test_tutorial_9_part_two.py +15 -0
  646. tests/test_tutorial_qm9_part_one.py +6 -0
  647. tests/testresources/refs/racs/generate_references.py +85 -0
  648. workflows/NandyJACSAu2022/bridge_functionalizer.py +253 -0
  649. workflows/NandyJACSAu2022/frag_functionalizer.py +242 -0
  650. workflows/NandyJACSAu2022/fragment_classes.py +586 -0
  651. workflows/NandyJACSAu2022/macrocycle_synthesis.py +179 -0
@@ -0,0 +1,1299 @@
1
+ import os
2
+ import re
3
+ import copy
4
+ import itertools
5
+ from scipy import sparse
6
+ import numpy as np
7
+ import pandas as pd
8
+ from typing import Tuple, List, Dict
9
+ from molSimplify.Classes.atom3D import atom3D
10
+ from molSimplify.Classes.mol3D import mol3D
11
+ from molSimplify.Scripts.cellbuilder_tools import import_from_cif
12
+ from molSimplify.Informatics.RACassemble import append_descriptors
13
+ from molSimplify.Informatics.autocorrelation import (
14
+ generate_atomonly_autocorrelations,
15
+ generate_atomonly_deltametrics,
16
+ generate_full_complex_autocorrelations,
17
+ generate_multimetal_autocorrelations,
18
+ generate_multimetal_deltametrics,
19
+ full_autocorrelation,
20
+ )
21
+ from molSimplify.Informatics.MOF.atomic import (
22
+ COVALENT_RADII,
23
+ )
24
+ from molSimplify.Informatics.MOF.PBC_functions import (
25
+ compute_adj_matrix,
26
+ compute_distance_matrix3,
27
+ compute_image_flag,
28
+ frac_coord,
29
+ fractional2cart,
30
+ get_closed_subgraph,
31
+ include_extra_shells,
32
+ ligand_detect,
33
+ linker_length,
34
+ mkcell,
35
+ readcif,
36
+ slice_mat,
37
+ write2file,
38
+ writeXYZandGraph,
39
+ XYZ_connected,
40
+ )
41
+
42
+
43
+ #### NOTE: In addition to molSimplify's dependencies, this portion requires
44
+ #### pymatgen to be installed. The RACs are intended to be computed
45
+ #### on the primitive cell of the material. You can compute them
46
+ #### using the commented out snippet of code if necessary.
47
+
48
+ # Example usage is given at the bottom of the script.
49
+
50
+ '''<<<< CODE TO COMPUTE PRIMITIVE UNIT CELLS >>>>'''
51
+ #########################################################################################
52
+ # This MOF RAC generator assumes that pymatgen is installed. #
53
+ # Pymatgen is used to get the primitive cell. #
54
+ #########################################################################################
55
+
56
+ ### Defining pymatgen function for getting primitive, since molSimplify does not depend on pymatgen.
57
+ # This function is commented out and should be uncommented if used.
58
+
59
+
60
+ def get_primitive(datapath, writepath, occupancy_tolerance=1):
61
+ """
62
+ Calculates and writes the primitive cell of the provided structure.
63
+
64
+ Parameters
65
+ ----------
66
+ datapath : str
67
+ The path to the cif file for which the primitive cell will be calculated.
68
+ writepath : str
69
+ The path to where the cif of the primitive cell will be written.
70
+ occupancy_tolerance : float
71
+ Scales down occupancies for a site to one, if they sum to below occupancy_tolerance.
72
+
73
+ Returns
74
+ -------
75
+ None
76
+
77
+ """
78
+ from pymatgen.io.cif import CifParser
79
+ s = CifParser(datapath, occupancy_tolerance=occupancy_tolerance).get_structures()[0]
80
+ sprim = s.get_primitive_structure()
81
+ sprim.to(writepath, "cif") # Output structure to a file.
82
+
83
+
84
+ '''<<<< END OF CODE TO COMPUTE PRIMITIVE UNIT CELLS >>>>'''
85
+
86
+
87
+ def load_sbu_lc_descriptors(sbupath: str) -> Tuple[str, pd.DataFrame, pd.DataFrame]:
88
+ """
89
+ Loads the sbu and lc descriptors.
90
+
91
+ Parameters
92
+ ----------
93
+ sbupath : str
94
+ Path of the folder to make a csv file in.
95
+
96
+ Returns
97
+ -------
98
+ sbu_descriptors : pandas.core.frame.DataFrame
99
+ The existing SBU descriptors.
100
+ lc_descriptors : pandas.core.frame.DataFrame
101
+ The existing lc descriptors.
102
+
103
+ """
104
+ sbu_descriptor_path = os.path.dirname(sbupath)
105
+ if os.path.getsize(sbu_descriptor_path + '/sbu_descriptors.csv') > 0: # Checking if there is a file there.
106
+ sbu_descriptors = pd.read_csv(sbu_descriptor_path + '/sbu_descriptors.csv')
107
+ else:
108
+ sbu_descriptors = pd.DataFrame()
109
+ if os.path.getsize(sbu_descriptor_path + '/lc_descriptors.csv') > 0: # Checking if there is a file there.
110
+ lc_descriptors = pd.read_csv(sbu_descriptor_path + '/lc_descriptors.csv')
111
+ else:
112
+ lc_descriptors = pd.DataFrame()
113
+
114
+ return sbu_descriptor_path, sbu_descriptors, lc_descriptors
115
+
116
+
117
+ def gen_and_append_desc(
118
+ temp_mol: mol3D, target_list, depth: int, descriptor_names: List[str],
119
+ descriptors: List[float], Gval: bool, feature_type: str) -> Tuple[Dict, List[str], List[float]]:
120
+ """
121
+ Generate and append descriptors, both standard and delta.
122
+
123
+ Parameters
124
+ ----------
125
+ temp_mol : molSimplify.Classes.mol3D.mol3D
126
+ mol3D object of the linker of interest.
127
+ target_list : list
128
+ The indices of the atoms of interest in the linker.
129
+ depth : int
130
+ The depth of the RACs that are generated. See https://doi.org/10.1021/acs.jpca.7b08750 for more information.
131
+ descriptor_names : list
132
+ The RAC descriptor names. Will be appended to.
133
+ descriptors : list
134
+ The RAC descriptor values. Will be appended to.
135
+ Gval : bool
136
+ Whether to use G value as RAC.
137
+ feature_type : str
138
+ Either 'lc' or 'func'.
139
+
140
+ Returns
141
+ -------
142
+ results_dictionary : dict
143
+ deltametrics RACs
144
+ descriptor_names : list
145
+ The updated RAC descriptor names.
146
+ descriptors : list
147
+ The updated RAC descriptor values.
148
+ """
149
+
150
+ results_dictionary = generate_atomonly_autocorrelations(
151
+ temp_mol, target_list, depth=depth, loud=False, oct=False,
152
+ polarizability=True, Gval=Gval
153
+ )
154
+ descriptor_names, descriptors = append_descriptors(
155
+ descriptor_names, descriptors, results_dictionary['colnames'],
156
+ results_dictionary['results'], feature_type, 'all'
157
+ )
158
+
159
+ results_dictionary = generate_atomonly_deltametrics(
160
+ temp_mol, target_list, depth=depth, loud=False, oct=False,
161
+ polarizability=True, Gval=Gval
162
+ )
163
+ descriptor_names, descriptors = append_descriptors(
164
+ descriptor_names, descriptors, results_dictionary['colnames'],
165
+ results_dictionary['results'], f'D_{feature_type}', 'all'
166
+ )
167
+
168
+ return results_dictionary, descriptor_names, descriptors
169
+
170
+ #########################################################################################
171
+ # The RAC functions here average over the different SBUs or linkers present. This is #
172
+ # because one MOF could have multiple different linkers or multiple SBUs, and we need #
173
+ # the vector to be of constant dimension so we can correlate the output property. #
174
+ #########################################################################################
175
+
176
+
177
+ def make_MOF_SBU_RACs(
178
+ SBUlist, SBU_subgraph, molcif, depth, name, cell_v, anchoring_atoms, sbupath,
179
+ linkeranchors_superlist, Gval, connections_list=False, connections_subgraphlist=False):
180
+ """
181
+ Generated RACs on the SBUs of the MOF, as well as on the lc atoms (SBU-connected atoms of linkers).
182
+
183
+ Parameters
184
+ ----------
185
+ SBUlist : list of lists of numpy.int64
186
+ Each inner list is its own separate SBU. The ints are the atom indices of that SBU. Length is # of SBUs.
187
+ SBU_subgraph : list of scipy.sparse.csr.csr_matrix
188
+ The atom connections in the SBU subgraph. Length is # of SBU.
189
+ molcif : molSimplify.Classes.mol3D.mol3D
190
+ The cell of the cif file being analyzed.
191
+ depth : int
192
+ The depth of the RACs that are generated. See https://doi.org/10.1021/acs.jpca.7b08750 for more information.
193
+ name : str
194
+ The name of the cif being analyzed.
195
+ cell_v : numpy.ndarray
196
+ The three Cartesian vectors representing the edges of the crystal cell. Shape is (3,3).
197
+ anchoring_atoms : set
198
+ Linker atoms that are bonded to a metal.
199
+ sbupath : str
200
+ Path of the folder to make a csv file in and TXT files containing connection index information.
201
+ linkeranchors_superlist : list of set
202
+ Coordinating atoms of linkers. Number of sets is the number of linkers.
203
+ Gval : bool
204
+ Whether to use G value as RAC.
205
+ connections_list : list of lists of int
206
+ Each inner list is its own separate linker. The ints are the atom indices of that linker. Length is # of linkers.
207
+ connections_subgraphlist : list of scipy.sparse.csr.csr_matrix
208
+ The atom connections in the linker subgraph. Length is # of linkers.
209
+
210
+ Returns
211
+ -------
212
+ names : list of str
213
+ The names of the RAC SBU features.
214
+ averaged_SBU_descriptors : numpy.ndarray
215
+ The values of the RAC SBU features, averaged over all SBUs.
216
+ lc_names : list of str
217
+ The names of the RAC lc (ligand coordinating I think) features.
218
+ averaged_lc_descriptors : numpy.ndarray
219
+ The values of the RAC lc features, averaged over all lc atoms.
220
+
221
+ """
222
+ descriptor_list = []
223
+ lc_descriptor_list: List[List[float]] = []
224
+ lc_names = []
225
+ names = []
226
+ descriptor_names = []
227
+ descriptors = []
228
+
229
+ sbu_descriptor_path, sbu_descriptors, lc_descriptors = load_sbu_lc_descriptors(sbupath)
230
+
231
+ global_connection_indices = []
232
+ for item in linkeranchors_superlist:
233
+ global_connection_indices.extend(list(item))
234
+
235
+ """""""""
236
+ Loop over all SBUs as identified by subgraphs. Then create the mol3Ds for each SBU.
237
+ """""""""
238
+ for i, SBU in enumerate(SBUlist):
239
+ descriptor_names = []
240
+ descriptors = []
241
+ SBU_mol = mol3D()
242
+ for val in SBU:
243
+ SBU_mol.addAtom(molcif.getAtom(val))
244
+ SBU_mol.graph = SBU_subgraph[i].todense()
245
+
246
+ """""""""
247
+ For each linker connected to the SBU, find the lc atoms for the lc-RACs.
248
+ lc atoms are those bonded to a metal.
249
+ """""""""
250
+ # lc_descriptors for SBU i
251
+ lc_descriptors_i: List[List[float]] = []
252
+ for j, linker in enumerate(connections_list): # Iterating over the different linkers
253
+ if len(set(SBU).intersection(linker)) > 0:
254
+ descriptor_names = []
255
+ descriptors = []
256
+ # This means that the SBU and the current linker are connected.
257
+ temp_mol = mol3D()
258
+ link_list = [] # Will hold the lc atoms for the current linker.
259
+ for jj, val2 in enumerate(linker): # linker is a list of global atom indices for the atoms in that linker
260
+ if val2 in anchoring_atoms:
261
+ link_list.append(jj)
262
+ # This builds a mol object for the linker --> even though it is in the SBU section.
263
+ temp_mol.addAtom(molcif.getAtom(val2))
264
+
265
+ temp_mol.graph = connections_subgraphlist[j].todense()
266
+ """""""""
267
+ Generate all of the lc autocorrelations (from the connecting atoms)
268
+ """""""""
269
+ results_dictionary, descriptor_names, descriptors = gen_and_append_desc(
270
+ temp_mol, link_list, depth, descriptor_names, descriptors, Gval, 'lc')
271
+ """""""""
272
+ If heteroatom functional groups exist (anything that is not C or H, so methyl is missed, also excludes anything lc, so carboxylic metal-coordinating oxygens skipped),
273
+ compile the list of atoms
274
+ """""""""
275
+ functional_atoms = []
276
+ for jj in range(len(temp_mol.graph)):
277
+ if jj not in link_list: # linker atom is not bonded to a metal
278
+ if not set({temp_mol.atoms[jj].sym}) & set({"C", "H"}): # not a carbon nor a hydrogen. syms get symbols.
279
+ functional_atoms.append(jj)
280
+ """""""""
281
+ Generate all of the functional group autocorrelations
282
+ """""""""
283
+ if len(functional_atoms) > 0:
284
+ results_dictionary, descriptor_names, descriptors = gen_and_append_desc(
285
+ temp_mol, functional_atoms, depth, descriptor_names, descriptors, Gval, 'func')
286
+ else: # There are no functional atoms.
287
+ if Gval:
288
+ num_atomic_properties = 7
289
+ else:
290
+ num_atomic_properties = 6
291
+
292
+ descriptor_names, descriptors = append_descriptors(
293
+ descriptor_names, descriptors, results_dictionary['colnames'],
294
+ list([np.zeros(int(num_atomic_properties*(depth + 1)))]), 'func', 'all'
295
+ )
296
+ descriptor_names, descriptors = append_descriptors(
297
+ descriptor_names, descriptors, results_dictionary['colnames'],
298
+ list([np.zeros(int(num_atomic_properties*(depth + 1)))]), 'D_func', 'all'
299
+ )
300
+
301
+ for val in descriptors:
302
+ if not (type(val) is float or isinstance(val, np.float64)):
303
+ print('Mixed typing. Please convert to python float, and avoid np float')
304
+ raise AssertionError('Mixed typing creates issues. Please convert your typing.')
305
+
306
+ lc_descriptors_i.append(descriptors)
307
+ if j == 0:
308
+ lc_names = descriptor_names
309
+
310
+ lc_descriptor_list.extend(lc_descriptors_i)
311
+ averaged_lc_descriptors = np.mean(np.array(lc_descriptor_list), axis=0) # Average the lc RACs over all of the linkers in the MOF.
312
+ lc_descriptor_df = pd.DataFrame(lc_descriptors_i, columns=lc_names)
313
+ lc_descriptor_df['name'] = name
314
+ # This CSV will be overwritten until the last SBU, but information on all linkers is being kept thanks to the concat function
315
+ lc_descriptors = pd.concat([lc_descriptors, lc_descriptor_df], ignore_index=True)
316
+ lc_descriptors.to_csv(sbu_descriptor_path+'/lc_descriptors.csv', index=False)
317
+ descriptors = []
318
+ descriptor_names = []
319
+ SBU_mol_cart_coords = np.array([atom.coords() for atom in SBU_mol.atoms])
320
+ SBU_mol_atom_labels = [atom.sym for atom in SBU_mol.atoms]
321
+ SBU_mol_adj_mat = np.array(SBU_mol.graph)
322
+
323
+ # WRITE THE SBU MOL TO THE PLACE
324
+ xyz_path = f'{sbupath}/{name}_sbu_{i}.xyz'
325
+ if not os.path.exists(xyz_path):
326
+ SBU_mol_fcoords_connected = XYZ_connected(cell_v, SBU_mol_cart_coords, SBU_mol_adj_mat)
327
+ writeXYZandGraph(xyz_path, SBU_mol_atom_labels, cell_v, SBU_mol_fcoords_connected, SBU_mol_adj_mat)
328
+
329
+ # Write TXT file indicating the connecting atoms
330
+ sbu_index_connection_indices = []
331
+ for item in global_connection_indices:
332
+ if item in SBU:
333
+ sbu_index_connection_indices.append(SBU.index(item))
334
+ sbu_index_connection_indices = list(np.sort(sbu_index_connection_indices)) # Sort in ascending order
335
+ sbu_index_connection_indices = [str(item) for item in sbu_index_connection_indices]
336
+ with open(f'{sbupath}/{name}_connection_indices_sbu_{i}.txt', 'w') as f:
337
+ f.write(' '.join(sbu_index_connection_indices))
338
+
339
+ """""""""
340
+ Generate all of the SBU based RACs (full scope, mc)
341
+ """""""""
342
+ results_dictionary = generate_full_complex_autocorrelations(
343
+ SBU_mol, depth=depth, loud=False, flag_name=False, Gval=Gval)
344
+ descriptor_names, descriptors = append_descriptors(
345
+ descriptor_names, descriptors, results_dictionary['colnames'], results_dictionary['results'], 'f', 'all')
346
+ # Now starts at every metal on the graph and autocorrelates
347
+
348
+ # Note, by this point in the code, molcif has had self.metals assigned to all metals in the structure
349
+ # with findMetal(transition_metals_only=False). So all metals are considered for mc and D_mc, not just
350
+ # transition metals
351
+
352
+ results_dictionary = generate_multimetal_autocorrelations(molcif, depth=depth, loud=False, Gval=Gval)
353
+ descriptor_names, descriptors = append_descriptors(
354
+ descriptor_names, descriptors, results_dictionary['colnames'], results_dictionary['results'], 'mc', 'all')
355
+ results_dictionary = generate_multimetal_deltametrics(molcif, depth=depth, loud=False, Gval=Gval)
356
+ descriptor_names, descriptors = append_descriptors(
357
+ descriptor_names, descriptors, results_dictionary['colnames'], results_dictionary['results'], 'D_mc', 'all')
358
+
359
+ # Add to DataFrame
360
+ sbu_descriptors_df = pd.DataFrame([descriptors], columns=descriptor_names)
361
+ sbu_descriptors_df["name"] = name
362
+ sbu_descriptors = pd.concat([sbu_descriptors, sbu_descriptors_df], ignore_index=True)
363
+ descriptor_list.append(descriptors)
364
+ if i == 0:
365
+ names = descriptor_names
366
+
367
+ sbu_descriptors.to_csv(sbu_descriptor_path+'/sbu_descriptors.csv', index=False)
368
+ averaged_SBU_descriptors = np.mean(np.array(descriptor_list), axis=0) # Average the SBU RACs over all of the SBUs in the MOF.
369
+ return names, averaged_SBU_descriptors, lc_names, averaged_lc_descriptors
370
+
371
+
372
+ def make_MOF_linker_RACs(
373
+ linkerlist, linker_subgraphlist, molcif, depth, name, cell_v,
374
+ linkerpath, linkeranchors_superlist, Gval):
375
+ """
376
+ Generate RACs on the linkers of the MOF.
377
+
378
+ Parameters
379
+ ----------
380
+ linkerlist : list of lists of int
381
+ Each inner list is its own separate linker. The ints are the atom indices of that linker. Length is # of linkers.
382
+ linker_subgraphlist : list of scipy.sparse.csr.csr_matrix
383
+ The atom connections in the linker subgraph. Length is # of linkers.
384
+ molcif : molSimplify.Classes.mol3D.mol3D
385
+ The cell of the cif file being analyzed.
386
+ depth : int
387
+ The depth of the RACs that are generated. See https://doi.org/10.1021/acs.jpca.7b08750 for more information.
388
+ name : str
389
+ The name of the cif being analyzed.
390
+ cell_v : numpy.ndarray
391
+ The three Cartesian vectors representing the edges of the crystal cell. Shape is (3,3).
392
+ linkerpath : str
393
+ Path of the folder to make a csv file in and TXT files containing connection index information.
394
+ linkeranchors_superlist : list of set
395
+ Coordinating atoms of linkers. Number of sets is the number of linkers.
396
+ Gval : bool
397
+ Whether to use G value as RAC.
398
+
399
+ Returns
400
+ -------
401
+ colnames : list of str
402
+ The names of the RAC linker features.
403
+ averaged_ligand_descriptors : numpy.ndarray
404
+ The values of the RAC linker features, averaged over all linkers.
405
+
406
+ """
407
+
408
+ #### This function makes full scope linker RACs for MOFs ####
409
+ descriptor_list = []
410
+ descriptors = []
411
+ if linkerpath:
412
+ linker_descriptor_path = os.path.dirname(linkerpath)
413
+ if os.path.getsize(linker_descriptor_path+'/linker_descriptors.csv') > 0: # Checking if there is a file there.
414
+ linker_descriptors = pd.read_csv(linker_descriptor_path+'/linker_descriptors.csv')
415
+ else:
416
+ linker_descriptors = pd.DataFrame()
417
+
418
+ global_connection_indices = []
419
+ for item in linkeranchors_superlist:
420
+ global_connection_indices.extend(list(item))
421
+
422
+ for i, linker in enumerate(linkerlist): # Iterating through the linkers.
423
+ # Preparing a mol3D object for the current linker.
424
+ linker_mol = mol3D()
425
+ for val in linker:
426
+ linker_mol.addAtom(molcif.getAtom(val))
427
+ linker_mol.graph = linker_subgraphlist[i].todense()
428
+
429
+ linker_mol_cart_coords = np.array([atom.coords() for atom in linker_mol.atoms])
430
+ linker_mol_atom_labels = [atom.sym for atom in linker_mol.atoms]
431
+ linker_mol_adj_mat = np.array(linker_mol.graph)
432
+
433
+ ###### WRITE THE LINKER MOL TO THE PLACE
434
+ xyz_path = f'{linkerpath}/{name}_linker_{i}.xyz'
435
+ if not os.path.exists(xyz_path):
436
+ linker_mol_fcoords_connected = XYZ_connected(cell_v, linker_mol_cart_coords, linker_mol_adj_mat)
437
+ writeXYZandGraph(xyz_path, linker_mol_atom_labels, cell_v, linker_mol_fcoords_connected, linker_mol_adj_mat)
438
+
439
+ # Write TXT file indicating the connecting atoms
440
+ linker_index_connection_indices = []
441
+ for item in global_connection_indices:
442
+ if item in linker:
443
+ linker_index_connection_indices.append(linker.index(item))
444
+ linker_index_connection_indices = list(np.sort(linker_index_connection_indices)) # Sort in ascending order
445
+ linker_index_connection_indices = [str(item) for item in linker_index_connection_indices]
446
+ with open(f'{linkerpath}/{name}_connection_indices_linker_{i}.txt', 'w') as f:
447
+ f.write(' '.join(linker_index_connection_indices))
448
+
449
+ allowed_strings = ['electronegativity', 'nuclear_charge', 'ident', 'topology', 'size']
450
+ labels_strings = ['chi', 'Z', 'I', 'T', 'S']
451
+ if Gval:
452
+ allowed_strings.append('group_number')
453
+ labels_strings.append('Gval')
454
+ colnames = []
455
+ lig_full = list()
456
+
457
+ """""""""
458
+ Generate all of the linker based RACs
459
+ """""""""
460
+ for ii, properties in enumerate(allowed_strings):
461
+ if not list(descriptors): # This is the case when just starting and the list is empty.
462
+ ligand_ac_full = full_autocorrelation(linker_mol, properties, depth) # RACs
463
+ else:
464
+ ligand_ac_full += full_autocorrelation(linker_mol, properties, depth)
465
+ this_colnames = []
466
+ for j in range(0, depth+1):
467
+ this_colnames.append('f-lig-'+labels_strings[ii] + '-' + str(j))
468
+ colnames.append(this_colnames)
469
+ lig_full.append(ligand_ac_full)
470
+
471
+ # Some formatting
472
+ lig_full = [item for sublist in lig_full for item in sublist] # flatten lists
473
+ colnames = [item for sublist in colnames for item in sublist]
474
+ linker_descriptors_df = pd.DataFrame([lig_full], columns=colnames)
475
+ linker_descriptors_df['name'] = name
476
+ linker_descriptors = pd.concat([linker_descriptors, linker_descriptors_df], ignore_index=True)
477
+ descriptor_list.append(lig_full)
478
+
479
+ # We dump the standard lc descriptors without averaging or summing so that the user
480
+ # can make the modifications that they want. By default we take the average ones.
481
+ linker_descriptors.to_csv(linker_descriptor_path+'/linker_descriptors.csv', index=False)
482
+ averaged_ligand_descriptors = np.mean(np.array(descriptor_list), axis=0)
483
+ return colnames, averaged_ligand_descriptors
484
+
485
+
486
+ def mkdir_if_absent(folder_paths):
487
+ """
488
+ Makes a folder at each path in folder_path if it does not yet exist.
489
+
490
+ Parameters
491
+ ----------
492
+ folder_path : list of str
493
+ The folder paths to check, and potentially at which to make a folder.
494
+
495
+ Returns
496
+ -------
497
+ None
498
+
499
+ """
500
+
501
+ for folder_path in folder_paths:
502
+ if not os.path.exists(folder_path):
503
+ os.mkdir(folder_path)
504
+
505
+
506
+ def make_file_if_absent(path, filenames):
507
+ """
508
+ Makes the specified files if they do not yet exist.
509
+
510
+ Parameters
511
+ ----------
512
+ path : str
513
+ The base path.
514
+ filenames : list of str
515
+ The file names.
516
+
517
+ Returns
518
+ -------
519
+ None
520
+
521
+ """
522
+
523
+ for filename in filenames:
524
+ if not os.path.exists(f'{path}/{filename}'):
525
+ with open(f'{path}/{filename}', 'w') as f:
526
+ f.close()
527
+
528
+
529
+ def path_maker(path):
530
+ """
531
+ Makes the required folders and files.
532
+
533
+ Parameters
534
+ ----------
535
+ path : str
536
+ The path to which output will be written.
537
+
538
+ Returns
539
+ -------
540
+ None
541
+
542
+ """
543
+ # Making the required folders
544
+ required_folders = [f'{path}/ligands', f'{path}/linkers', f'{path}/sbus', f'{path}/xyz', f'{path}/logs']
545
+ mkdir_if_absent(required_folders)
546
+
547
+ # Making the required files
548
+ required_files = ['sbu_descriptors.csv', 'linker_descriptors.csv', 'lc_descriptors.csv']
549
+ make_file_if_absent(path, required_files)
550
+
551
+
552
+ def failure_response(path, failure_str):
553
+ """
554
+ Writes to the log file about the encountered failure.
555
+
556
+ Parameters
557
+ ----------
558
+ path : str
559
+ The path to which output will be written.
560
+
561
+ Returns
562
+ -------
563
+ Two zero lists to indicate failure.
564
+
565
+ """
566
+ full_names = [0]
567
+ full_descriptors = [0]
568
+ write2file(path, "/FailedStructures.log", failure_str)
569
+ return full_names, full_descriptors
570
+
571
+
572
+ def bond_information_write(linker_list, linkeranchors_superlist, adj_matrix, molcif, cell_v, path):
573
+ """
574
+ Attains and writes bond information about the bonds between SBUs and linkers.
575
+
576
+ Parameters
577
+ ----------
578
+ linker_list : list of lists of ints
579
+ Each inner list is its own separate linker. The ints are the atom indices of that linker. Length is # of linkers.
580
+ linkeranchors_superlist : list of set
581
+ Coordinating atoms of linkers. Number of sets is the number of linkers.
582
+ adj_matrix : scipy.sparse.csr.csr_matrix
583
+ 1 represents a bond, 0 represents no bond. Shape is (number of atoms, number of atoms).
584
+ molcif : molSimplify.Classes.mol3D.mol3D
585
+ The cell of the cif file being analyzed.
586
+ cell_v : numpy.ndarray
587
+ The three Cartesian vectors representing the edges of the crystal cell. Shape is (3,3).
588
+ path : str
589
+ The parent path to which output will be written.
590
+
591
+ Returns
592
+ -------
593
+ None
594
+
595
+ """
596
+
597
+ bond_length_list = []
598
+ scaled_bond_length_list = []
599
+ for linker_idx, linker_atoms_list in enumerate(linker_list): # Iterate over all linkers
600
+ # Getting the connection points of the linker
601
+ for anchor_super_idx in range(len(linkeranchors_superlist)):
602
+ if list(linkeranchors_superlist[anchor_super_idx])[0] in linker_atoms_list: # Any anchor index in the current entry of linkeranchors_superlist is in the current linker's indices
603
+ linker_connection_points = list(linkeranchors_superlist[anchor_super_idx]) # Indices of the connection points in the linker
604
+ for con_point in linker_connection_points:
605
+ connected_atoms = adj_matrix.todense()[con_point, :]
606
+ connected_atoms = np.ravel(connected_atoms)
607
+
608
+ connected_atoms = np.nonzero(connected_atoms)[0] # The indices of atoms connected to atom with index con_point.
609
+
610
+ for con_atom in connected_atoms:
611
+ con_atom3D = molcif.getAtom(con_atom) # atom3D of an atom connected to the connection point
612
+ con_point3D = molcif.getAtom(con_point) # atom3D of the connection point on the linker
613
+ # Check if the atom is a metal
614
+ if con_atom3D.ismetal(transition_metals_only=False):
615
+ # Finding the optimal unit cell shift
616
+ molcif_cart_coords = np.array([atom.coords() for atom in molcif.atoms])
617
+ fcoords = frac_coord(molcif_cart_coords, cell_v) # fractional coordinates
618
+ fcoords[con_atom] += compute_image_flag(cell_v, fcoords[con_point], fcoords[con_atom]) # Shifting the connected metal to get it close to the connection point
619
+ ccoords = fractional2cart(fcoords, cell_v)
620
+ shifted_con_atom3D = atom3D(Sym=con_atom3D.symbol(), xyz=list(ccoords[con_atom, :]))
621
+
622
+ bond_len = shifted_con_atom3D.distance(con_point3D) # Bond length between the connected metal and the connection point.
623
+ con_atom_radius = COVALENT_RADII[shifted_con_atom3D.symbol()]
624
+ con_point_radius = COVALENT_RADII[con_point3D.symbol()]
625
+ relative_bond_len = bond_len / (con_atom_radius + con_point_radius)
626
+
627
+ bond_length_list.append(bond_len)
628
+ scaled_bond_length_list.append(relative_bond_len)
629
+
630
+ mean_bond_len = np.mean(bond_length_list) # Average over all SBU-linker atom to atom connections
631
+ mean_scaled_bond_len = np.mean(scaled_bond_length_list) # Average over all SBU-linker atom to atom connections
632
+ std_bond_len = np.std(bond_length_list)
633
+ std_scaled_bond_len = np.std(scaled_bond_length_list)
634
+
635
+ with open(f"{path}/sbu_linker_bondlengths.txt", "w") as f:
636
+ f.write(f'Mean bond length: {mean_bond_len}\n')
637
+ f.write(f'Mean scaled bond length: {mean_scaled_bond_len}\n')
638
+ f.write(f'Stdev bond length: {std_bond_len}\n')
639
+ f.write(f'Stdev scaled bond length: {std_scaled_bond_len}')
640
+
641
+
642
+ def surrounded_sbu_gen(SBU_list, linker_list, sbupath, molcif, adj_matrix, cell_v, allatomtypes, name):
643
+ """
644
+ Writes XYZ files for all SBUs provided, with each SBU surrounded by all linkers coordinated to it.
645
+ Also generates TXT files indicating indices of SBUs in the XYZs.
646
+
647
+ Parameters
648
+ ----------
649
+ SBU_list : list of lists of ints
650
+ Each inner list is its own separate SBU. The ints are the atom indices of that SBU. Length is # of SBUs.
651
+ linker_list : list of lists of ints
652
+ Each inner list is its own separate linker. The ints are the atom indices of that linker. Length is # of linkers.
653
+ sbupath : str
654
+ The path to which SBU information is written.
655
+ molcif : molSimplify.Classes.mol3D.mol3D
656
+ The cell of the cif file being analyzed.
657
+ adj_matrix : scipy.sparse.csr.csr_matrix
658
+ 1 represents a bond, 0 represents no bond. Shape is (number of atoms, number of atoms).
659
+ cell_v : numpy.ndarray
660
+ The three Cartesian vectors representing the edges of the crystal cell. Shape is (3,3).
661
+ allatomtypes : list of str
662
+ The atom types of the cif file, indicated by periodic symbols like 'O' and 'Cu'. Length is the number of atoms.
663
+ name : str
664
+ The name of the cif being analyzed.
665
+
666
+ Returns
667
+ -------
668
+ None
669
+
670
+ """
671
+
672
+ for SBU_idx, atoms_sbu in enumerate(SBU_list):
673
+ # atoms_sbu are the indices of atoms in the SBU with index SBU_idx
674
+
675
+ connection_atoms = [] # List of lists of the coordinating atoms of each of the connected linkers. Length is # of connected linkers.
676
+ atoms_connected_linkers = [] # List of lists of the atoms of each of the connected linkers. Length is # of connected linkers.
677
+ for atoms_linker in linker_list:
678
+ atoms_in_common = list(set(atoms_sbu).intersection(set(atoms_linker)))
679
+ if len(atoms_in_common) != 0:
680
+ connection_atoms.append(atoms_in_common)
681
+ atoms_connected_linkers.append(atoms_linker)
682
+
683
+ # Generating an XYZ of the SBU surrounded by linkers.
684
+ xyz_path = f'{sbupath}/{name}_sbu_{SBU_idx}_with_linkers.xyz'
685
+ # Also generating a TXT file of local indices.
686
+ txt_path = f'{sbupath}/{name}_sbu_{SBU_idx}_with_linkers_idx.txt'
687
+ # For each atom index in an inner list in connection_atoms, build out the corresponding linker (inner list) in atoms_connected_linkers.
688
+
689
+ ### Start with the atoms of the SBU
690
+ surrounded_sbu = mol3D() # SBU surrounded by linkers
691
+ starting_atom_idx = atoms_sbu[0]
692
+ added_idx = [starting_atom_idx] # This list will contain the SBU indices that no longer need to be considered for branching.
693
+ starting_atom3D = molcif.getAtom(starting_atom_idx)
694
+ # The mol3D object starts out with a single atom. Atoms will be added branching out from this initial atom.
695
+ surrounded_sbu.addAtom(starting_atom3D)
696
+ atom3D_dict = {starting_atom_idx: starting_atom3D} # atom3D objects of the SBU
697
+
698
+ dense_adj_mat = np.array(adj_matrix.todense())
699
+
700
+ # Dictionary. Keys are ints (indices of atoms), values are lists of indices of atoms
701
+ # The key is the atom relative to which the new atom must be positioned.
702
+ atoms_connected_to_start = list(np.nonzero(dense_adj_mat[starting_atom_idx])[0])
703
+ atoms_connected_to_start = [i for i in atoms_connected_to_start if i in atoms_sbu]
704
+ sbu_atoms_to_branch_from = {starting_atom_idx: atoms_connected_to_start}
705
+ sbu_atoms_to_branch_from_keys = [starting_atom_idx]
706
+
707
+ while len(sbu_atoms_to_branch_from_keys) != 0:
708
+ # Take from the first key, i.e. [0], of the dictionary
709
+ my_key = sbu_atoms_to_branch_from_keys[0]
710
+ neighbor_idx = sbu_atoms_to_branch_from[my_key][0] # Grabbing a neighbor to calculate its position.
711
+
712
+ # Remove that index from further consideration
713
+ sbu_atoms_to_branch_from[my_key].remove(neighbor_idx)
714
+
715
+ # If the list associated with a key is now empty, remove the key.
716
+ if len(sbu_atoms_to_branch_from[my_key]) == 0:
717
+ sbu_atoms_to_branch_from_keys.remove(my_key) # sbu_atoms_to_branch_from_keys = [i for i in sbu_atoms_to_branch_from_keys if i != my_key]
718
+ sbu_atoms_to_branch_from.pop(my_key)
719
+
720
+ if neighbor_idx in added_idx:
721
+ continue # Skip this index if it has already been added
722
+
723
+ # Getting the optimal position of the neighbor, relative to my_key
724
+ fcoords_my_key = frac_coord(atom3D_dict[my_key].coords(), cell_v)
725
+
726
+ fcoords_neighbor_initial = frac_coord(molcif.getAtom(neighbor_idx).coords(), cell_v)
727
+ fcoords_neighbor = fcoords_neighbor_initial + compute_image_flag(cell_v, fcoords_my_key, fcoords_neighbor_initial)
728
+ coords_neighbor = fractional2cart(fcoords_neighbor, cell_v)
729
+ symbol_neighbor = allatomtypes[neighbor_idx] # Element
730
+ new_atom3D = atom3D(Sym=symbol_neighbor, xyz=coords_neighbor)
731
+ surrounded_sbu.addAtom(new_atom3D)
732
+
733
+ atom3D_dict[neighbor_idx] = new_atom3D
734
+ added_idx.append(neighbor_idx)
735
+ atoms_connected_to_neighbor = list(np.nonzero(dense_adj_mat[neighbor_idx])[0])
736
+ atoms_connected_to_neighbor_to_check = [i for i in atoms_connected_to_neighbor if i not in added_idx and i in atoms_sbu]
737
+ if len(atoms_connected_to_neighbor_to_check) > 0:
738
+ sbu_atoms_to_branch_from[neighbor_idx] = atoms_connected_to_neighbor_to_check
739
+ sbu_atoms_to_branch_from_keys.append(neighbor_idx)
740
+
741
+ # At this point in the code, all SBU atoms have been added to the mol3D object surrounded_sbu.
742
+ sbu_indices_local = [*range(len(added_idx))]
743
+ connection_points_local = [added_idx.index(j) for i in connection_atoms for j in i]
744
+ connection_points_local.sort()
745
+
746
+ ### Next, add each of the linkers.
747
+ # Using atom3D_dict, connection_atoms, and atoms_connected_linkers.
748
+ for linker_idx in range(len(connection_atoms)):
749
+ # For each linker, build out the linker in surrounded_sbu object.
750
+
751
+ linker_indices = atoms_connected_linkers[linker_idx]
752
+
753
+ for starting_atom_idx in connection_atoms[linker_idx]:
754
+ atom3D_dict_copy = atom3D_dict.copy()
755
+ added_idx = [starting_atom_idx]
756
+
757
+ atoms_connected_to_start = list(np.nonzero(dense_adj_mat[starting_atom_idx])[0])
758
+ atoms_connected_to_start = [i for i in atoms_connected_to_start if i in linker_indices]
759
+ linker_atoms_to_branch_from = {starting_atom_idx: atoms_connected_to_start}
760
+ linker_atoms_to_branch_from_keys = [starting_atom_idx]
761
+
762
+ while len(linker_atoms_to_branch_from_keys) != 0:
763
+
764
+ # Take from the first key, i.e. [0], of the dictionary
765
+ my_key = linker_atoms_to_branch_from_keys[0]
766
+ neighbor_idx = linker_atoms_to_branch_from[my_key][0] # Grabbing a neighbor to calculate its position.
767
+
768
+ # Remove that index from further consideration
769
+ linker_atoms_to_branch_from[my_key].remove(neighbor_idx)
770
+
771
+ # If the list associated with a key is now empty, remove the key.
772
+ if len(linker_atoms_to_branch_from[my_key]) == 0:
773
+ linker_atoms_to_branch_from_keys.remove(my_key)
774
+ linker_atoms_to_branch_from.pop(my_key)
775
+
776
+ if neighbor_idx in added_idx:
777
+ continue # Skip this index if it has already been added
778
+
779
+ # Getting the optimal position of the neighbor, relative to my_key
780
+ fcoords_my_key = frac_coord(atom3D_dict_copy[my_key].coords(), cell_v)
781
+
782
+ fcoords_neighbor_initial = frac_coord(molcif.getAtom(neighbor_idx).coords(), cell_v)
783
+ fcoords_neighbor = fcoords_neighbor_initial + compute_image_flag(cell_v, fcoords_my_key, fcoords_neighbor_initial)
784
+ coords_neighbor = fractional2cart(fcoords_neighbor, cell_v)
785
+ symbol_neighbor = allatomtypes[neighbor_idx] # Element
786
+ new_atom3D = atom3D(Sym=symbol_neighbor, xyz=coords_neighbor)
787
+
788
+ # Only add the new atom if it does not overlap with an atom that is already in surrounded sbu.
789
+ # If there is overlap, then the atom was already added in the SBU.
790
+ min_dist = 100 # Starting from a big number that will be replaced in the subsequent lines.
791
+ num_atoms = surrounded_sbu.getNumAtoms()
792
+ for i in range(num_atoms):
793
+ pair_dist = new_atom3D.distance(surrounded_sbu.getAtom(i))
794
+ if pair_dist < min_dist:
795
+ min_dist = pair_dist
796
+ if min_dist > 0.1:
797
+ surrounded_sbu.addAtom(new_atom3D)
798
+
799
+ atom3D_dict_copy[neighbor_idx] = new_atom3D
800
+ added_idx.append(neighbor_idx)
801
+ atoms_connected_to_neighbor = list(np.nonzero(dense_adj_mat[neighbor_idx])[0])
802
+ atoms_connected_to_neighbor_to_check = [i for i in atoms_connected_to_neighbor if i not in added_idx and i in linker_indices]
803
+ if len(atoms_connected_to_neighbor_to_check) > 0:
804
+ linker_atoms_to_branch_from[neighbor_idx] = atoms_connected_to_neighbor_to_check
805
+ linker_atoms_to_branch_from_keys.append(neighbor_idx)
806
+
807
+ surrounded_sbu.writexyz(xyz_path)
808
+
809
+ # Write TXT file of index information.
810
+ with open(txt_path, 'w') as f:
811
+ f.write(f'SBU indices: {sbu_indices_local}\n')
812
+ f.write(f'connection indices: {connection_points_local}')
813
+
814
+
815
+ def dist_mat_comp(X):
816
+ """
817
+ Computes the pairwise distances between the rows of the coordinate information X.
818
+
819
+ Parameters
820
+ ----------
821
+ X : numpy.ndarray
822
+ Cartesian coordinate information for atoms. Shape is (number of atoms, 3).
823
+
824
+ Returns
825
+ -------
826
+ dist_mat : numpy.ndarray
827
+ Pairwise distances between all atoms. Shape is (number of atoms, number of atoms).
828
+
829
+ """
830
+
831
+ # Assumes X is an np array of shape (number of atoms, 3). The Cartesian coordinates of atoms.
832
+ # Does not do any unit cell shifts
833
+ # Makes use of numpy vectorization to speed things up versus a for loop approach.
834
+ X1 = np.expand_dims(X, axis=1)
835
+ X2 = np.expand_dims(X, axis=0)
836
+ Z = X1 - X2
837
+ dist_mat = np.sqrt(np.sum(np.square(Z), axis=-1)) # The pairwise distance matrix. Distances between all atoms.
838
+ return dist_mat
839
+
840
+
841
+ def detect_1D_rod(SBU_list, molcif, allatomtypes, cell_v, logpath, name):
842
+ """
843
+ Writes to the log file if the MOF is likely to contain a 1D rod.
844
+
845
+ Parameters
846
+ ----------
847
+ SBU_list : list of lists of ints
848
+ Each inner list is its own separate SBU. The ints are the atom indices of that SBU. Length is # of SBUs.
849
+ molcif : molSimplify.Classes.mol3D.mol3D
850
+ The cell of the cif file being analyzed.
851
+ allatomtypes : list of str
852
+ The atom types of the cif file, indicated by periodic symbols like 'O' and 'Cu'. Length is the number of atoms.
853
+ cell_v : numpy.ndarray
854
+ The three Cartesian vectors representing the edges of the crystal cell. Shape is (3,3).
855
+ logpath : str
856
+ The path to which log files are written.
857
+ name : str
858
+ The name of the cif being analyzed.
859
+
860
+ Returns
861
+ -------
862
+ None
863
+
864
+ """
865
+
866
+ sbu_atom_indices = []
867
+ for i in SBU_list:
868
+ # i is the indices in a given SBU
869
+ sbu_atom_indices.extend(i)
870
+ sbu_atom_indices.sort()
871
+
872
+ # allatomtypes_sbus_initial = [i for idx, i in enumerate(allatomtypes) if idx in sbu_atom_indices]
873
+ cart_coords_sbus_initial = [molcif.getAtom(i).coords() for i in sbu_atom_indices]
874
+ allatomtypes_sbus_with_shifts = [] # Will contain the symbols of all SBU atoms, across the 8 unit cell shifts
875
+ cart_coords_sbus_with_shifts = [] # Will contain the cartesian coordinates of all SBU atoms, across the 8 unit cell shifts
876
+
877
+ # Applying all possible unit cell shifts in 0, 1, for all SBU atoms
878
+ for idx, i in enumerate(sbu_atom_indices):
879
+ supercells = np.array(list(itertools.product((0, 1), repeat=3)))
880
+ fractional_coords = frac_coord(cart_coords_sbus_initial[idx], cell_v)
881
+ fractional_coords_shifts = fractional_coords + supercells # 8 versions of fractional_coords, shifted some cells over in different directions
882
+ for j in fractional_coords_shifts:
883
+ allatomtypes_sbus_with_shifts.append(allatomtypes[i])
884
+ cart_coords_sbus_with_shifts.append(fractional2cart(j, cell_v))
885
+
886
+ cart_coords_sbus_with_shifts = np.array(cart_coords_sbus_with_shifts) # Converting nested list to a numpy array
887
+
888
+ distance_mat = dist_mat_comp(cart_coords_sbus_with_shifts)
889
+ adj_matrix, _ = compute_adj_matrix(distance_mat, allatomtypes_sbus_with_shifts, handle_overlap=True) # Ignoring overlap
890
+
891
+ # For each connected component, see how long it is
892
+ adj_matrix = sparse.csr_matrix(adj_matrix)
893
+ n_components, labels_components = sparse.csgraph.connected_components(csgraph=adj_matrix, directed=False, return_labels=True)
894
+
895
+ # What is the shortest cell vector?
896
+ min_vec_len = np.min(np.linalg.norm(cell_v, axis=1)) # Equivalent to min(cpar[:3])
897
+
898
+ is_1d_rod = False
899
+ for i in range(n_components):
900
+ component_indices = np.where(labels_components == i)[0]
901
+ component_cart_coords = cart_coords_sbus_with_shifts[component_indices]
902
+
903
+ pairwise_atom_distances = dist_mat_comp(component_cart_coords)
904
+ if np.max(pairwise_atom_distances) > min_vec_len:
905
+ # In this case, an SBU likely stretches out longer than a unit cell
906
+ is_1d_rod = True
907
+ break
908
+
909
+ if is_1d_rod:
910
+ print('Likely 1D rod')
911
+ tmpstr = "MOF SBU is likely a 1D rod"
912
+ write2file(logpath, "/%s.log" % name, tmpstr)
913
+
914
+
915
+ def get_MOF_descriptors(
916
+ data, depth, path=False, xyzpath=False, graph_provided=False, wiggle_room=1,
917
+ max_num_atoms=2000, get_sbu_linker_bond_info=False, surrounded_sbu_file_generation=False,
918
+ detect_1D_rod_sbu=False, Gval=False):
919
+ """
920
+ Generates RAC descriptors on a MOF, assuming it has P1 symmetry.
921
+ Writes three files: sbu_descriptors.csv, linker_descriptors.csv, and lc_descriptors.csv
922
+ These files contain the RAC descriptors of the MOF.
923
+
924
+ Parameters
925
+ ----------
926
+ data : str
927
+ The path to the cif file for which descriptors are generated.
928
+ depth : int
929
+ The depth of the RACs that are generated. See https://doi.org/10.1021/acs.jpca.7b08750 for more information.
930
+ path : str
931
+ The parent path to which output will be written.
932
+ This output includes three csv files.
933
+ This output also includes three folders called ligands, linkers, and sbus.
934
+ These folders contain net and xyz files of the components of the MOF.
935
+ This output also includes a folder called logs.
936
+ This output also includes the xyz and net files for the cif being analyzed, written with the function writeXYZandGraph.
937
+ xyzpath : str
938
+ The path to where the xyz of the MOF structure will be written.
939
+ graph_provided : bool
940
+ Whether or not the cif file has graph information of the structure (i.e. what atoms are bonded to what atoms).
941
+ If not, computes the N^2 pairwise distance matrix, which is expensive.
942
+ wiggle_room : float
943
+ A multiplier that allows for more or less strict bond distance cutoffs.
944
+ max_num_atoms : int
945
+ The maximum number of atoms in the unit cell for which analysis is conducted.
946
+ get_sbu_linker_bond_info : bool
947
+ Whether or not a TXT file is written with information on the bonds between SBUs and linkers.
948
+ surrounded_sbu_file_generation : bool
949
+ Whether or not an XYZ file for each SBU, surrounded by its connected linkers, will be generated.
950
+ detect_1D_rod_sbu : bool
951
+ Whether or not to check if SBU is a 1D rod.
952
+ Gval : bool
953
+ Whether to use G value as RAC, by default False.
954
+
955
+ Returns
956
+ -------
957
+ full_names : list of str
958
+ The names of the RAC features.
959
+ full_descriptors : list of numpy.float64
960
+ The values of the RAC features.
961
+
962
+ """
963
+
964
+ if not path: # Throw an error if the user did not supply a path to which to write the output.
965
+ print('Need a directory to place all of the linker, SBU, and ligand objects. Exiting now.')
966
+ raise ValueError('Base path must be specified in order to write descriptors.')
967
+ else:
968
+ if path.endswith('/'):
969
+ path = path[:-1]
970
+
971
+ # Making the required folders and files.
972
+ path_maker(path)
973
+
974
+ ligandpath = path+'/ligands'
975
+ linkerpath = path+'/linkers'
976
+ sbupath = path+'/sbus'
977
+ logpath = path+"/logs"
978
+
979
+ """""""""
980
+ Input cif file and get the cell parameters and adjacency matrix. If too large or has overlap, do not featurize.
981
+ Simultaneously prepare mol3D class for MOF for future RAC featurization (molcif).
982
+ """""""""
983
+ cpar, allatomtypes, fcoords = readcif(data)
984
+ cell_v = mkcell(cpar)
985
+ cart_coords = fractional2cart(fcoords, cell_v)
986
+ name = os.path.basename(data).replace(".cif", "")
987
+ if len(cart_coords) > max_num_atoms: # Don't deal with large cifs because of computational resources required for their treatment.
988
+ print("cif file is too large, skipping it for now...")
989
+ failure_str = f"Failed to featurize {name}: large primitive cell\n {len(cart_coords)} atoms"
990
+ full_names, full_descriptors = failure_response(path, failure_str)
991
+ return full_names, full_descriptors
992
+
993
+ """""""""
994
+ Getting the adjacency matrix.
995
+ """""""""
996
+ if not graph_provided: # Make the adjacency matrix.
997
+ distance_mat = compute_distance_matrix3(cell_v, cart_coords)
998
+ try:
999
+ adj_matrix, _ = compute_adj_matrix(distance_mat, allatomtypes, wiggle_room)
1000
+ except NotImplementedError:
1001
+ failure_str = f"Failed to featurize {name}: atomic overlap\n"
1002
+ full_names, full_descriptors = failure_response(path, failure_str)
1003
+ return full_names, full_descriptors
1004
+ else: # Grab the adjacency matrix from the cif file.
1005
+ adj_matrix_list = []
1006
+ max_sofar = 0
1007
+ with open(data.replace('primitive', 'cif'), 'r') as f:
1008
+ readdata = f.readlines()
1009
+ flag = False
1010
+ for i, row in enumerate(readdata):
1011
+ if '_ccdc_geom_bond_type' in row:
1012
+ flag = True
1013
+ continue
1014
+ if flag:
1015
+ splitrow = row.split()
1016
+ atom1 = int(re.findall(r'\d+', splitrow[0])[0])
1017
+ atom2 = int(re.findall(r'\d+', splitrow[1])[0])
1018
+ max_sofar = max(atom1, max_sofar)
1019
+ max_sofar = max(atom2, max_sofar)
1020
+ adj_matrix_list.append((atom1, atom2))
1021
+ adj_matrix = np.zeros((max_sofar + 1, max_sofar + 1)) # 0 indicates the absence of a bond.
1022
+ for i, row in enumerate(adj_matrix_list):
1023
+ adj_matrix[row[0], row[1]] = 1 # 1 is indicative of a bond.
1024
+ adj_matrix[row[1], row[0]] = 1
1025
+ adj_matrix = sparse.csr_matrix(adj_matrix)
1026
+
1027
+ writeXYZandGraph(xyzpath, allatomtypes, cell_v, fcoords, adj_matrix.todense())
1028
+ molcif, _, _, _, _ = import_from_cif(data, True) # molcif is a mol3D class of a single unit cell (or the cell of the cif file)
1029
+ molcif.graph = adj_matrix.todense()
1030
+
1031
+ """""""""
1032
+ check number of connected components.
1033
+ if more than 1: it checks if the structure is interpenetrated. Fails if no metal in one of the connected components (identified by the graph).
1034
+ This includes floating solvent molecules.
1035
+ """""""""
1036
+
1037
+ n_components, labels_components = sparse.csgraph.connected_components(csgraph=adj_matrix, directed=False, return_labels=True)
1038
+ metal_list = set([at for at in molcif.findMetal(transition_metals_only=False)]) # the atom indices of the metals
1039
+ # print('##### METAL LIST', metal_list, [molcif.getAtom(val).symbol() for val in list(metal_list)])
1040
+ # print('##### METAL LIST', metal_list, [val.symbol() for val in molcif.atoms])
1041
+ if not len(metal_list) > 0:
1042
+ failure_str = f"Failed to featurize {name}: no metal found\n"
1043
+ full_names, full_descriptors = failure_response(path, failure_str)
1044
+ return full_names, full_descriptors
1045
+ for comp in range(n_components):
1046
+ inds_in_comp = [i for i in range(len(labels_components)) if labels_components[i] == comp]
1047
+ if not set(inds_in_comp) & metal_list: # In the context of sets, & is the intersection. If the intersection is null, the (&) expression is False; the `not` would then make it True.
1048
+ # If this if statement is entered, there is an entire connected component that has no metals in it. No connections to any metal.
1049
+ failure_str = f"Failed to featurize {name}: solvent molecules\n"
1050
+ full_names, full_descriptors = failure_response(path, failure_str)
1051
+ return full_names, full_descriptors
1052
+
1053
+ if n_components > 1: # There are multiple connected components that have a metal in them in this case.
1054
+ print("structure is interpenetrated")
1055
+ tmpstr = "%s found to be an interpenetrated structure\n" % (name)
1056
+ write2file(logpath, "/%s.log" % name, tmpstr)
1057
+
1058
+ """""""""
1059
+ step 1: metallic part
1060
+ removelist = metals (1) + atoms only connected to metals (2) + H connected to (1+2)
1061
+ Actually, it looks like only (1) and (2). Not H connected to (1+2)
1062
+ SBUlist = removelist + 1st coordination shell of the metals
1063
+ removelist = set()
1064
+ Logs the atom types of the connecting atoms to the metal in logpath.
1065
+ """""""""
1066
+ SBUlist = set()
1067
+ metal_list = set([at for at in molcif.findMetal(transition_metals_only=False)]) # the atom indices of the metals
1068
+ # print('##### METAL LIST2', metal_list, [molcif.getAtom(val).symbol() for val in list(metal_list)])
1069
+ # print('##### all LIST2', metal_list, [val.symbol() for val in molcif.atoms])
1070
+ [SBUlist.update(set([metal])) for metal in molcif.findMetal(transition_metals_only=False)] # Consider all metals as part of the SBUs.
1071
+ [SBUlist.update(set(molcif.getBondedAtomsSmart(metal))) for metal in molcif.findMetal(transition_metals_only=False)] # atoms connected to metals.
1072
+ removelist = set()
1073
+ [removelist.update(set([metal])) for metal in molcif.findMetal(transition_metals_only=False)] # Remove all metals as part of the SBUs.
1074
+ for metal in removelist:
1075
+ bonded_atoms = set(molcif.getBondedAtomsSmart(metal))
1076
+ bonded_atoms_types = set([str(allatomtypes[at]) for at in set(molcif.getBondedAtomsSmart(metal))]) # The types of elements bonded to metals. E.g. oxygen, carbon, etc.
1077
+ cn = len(bonded_atoms)
1078
+ cn_atom = ",".join([at for at in bonded_atoms_types])
1079
+ tmpstr = "atom %i with type of %s found to have %i coordinates with atom types of %s\n"%(metal,allatomtypes[metal],cn,cn_atom)
1080
+ write2file(logpath, "/%s.log" % name, tmpstr)
1081
+ [removelist.update(set([atom])) for atom in SBUlist if all((molcif.getAtom(val).ismetal() or molcif.getAtom(val).symbol().upper() == 'H') for val in molcif.getBondedAtomsSmart(atom))]
1082
+ """""""""
1083
+ adding hydrogens connected to atoms which are only connected to metals. In particular interstitial OH, like in UiO SBU.
1084
+ """""""""
1085
+ for atom in SBUlist:
1086
+ for val in molcif.getBondedAtomsSmart(atom):
1087
+ if molcif.getAtom(val).symbol().upper() == 'H':
1088
+ removelist.update(set([val]))
1089
+
1090
+ """""""""
1091
+ At this point:
1092
+ The remove list only removes metals and things ONLY connected to metals or hydrogens.
1093
+ Thus the coordinating atoms are double counted in the linker.
1094
+
1095
+ step 2: organic part
1096
+ removelist = linkers are all atoms - the removelist (assuming no bond between
1097
+ organiclinkers)
1098
+ """""""""
1099
+ allatoms = set(range(0, adj_matrix.shape[0])) # The indices of all the atoms.
1100
+ linkers = allatoms - removelist
1101
+ linker_list, linker_subgraphlist = get_closed_subgraph(linkers.copy(), removelist.copy(), adj_matrix)
1102
+ connections_list = copy.deepcopy(linker_list)
1103
+ connections_subgraphlist = copy.deepcopy(linker_subgraphlist)
1104
+ """""""""
1105
+ find all anchoring atoms on linkers and ligands (lc identification)
1106
+ The atoms that are bonded to a metal.
1107
+ """""""""
1108
+ anc_atoms = set()
1109
+ for linker in linker_list: # Checking all of the linkers one by one.
1110
+ for atom_linker in linker: # Checking each atom in the current linker.
1111
+ bonded2atom = np.nonzero(adj_matrix[atom_linker, :])[1] # indices of atoms with bonds to the atom with the index atom_linker
1112
+ if set(bonded2atom) & metal_list: # This means one of the atoms bonded to the atom with the index atom_linker is a metal.
1113
+ anc_atoms.add(atom_linker)
1114
+ """""""""
1115
+ step 3: determine whether linker or ligand
1116
+ checking to find the anchors and #SBUs that are connected to an organic part
1117
+ anchor <= 1 -> ligand
1118
+ anchor > 1 and #SBU > 1 -> linker
1119
+ else: walk over the linker graph and count #crossing PBC
1120
+ if #crossing is odd -> linker
1121
+ else -> ligand
1122
+ """""""""
1123
+ initial_SBU_list, initial_SBU_subgraphlist = get_closed_subgraph(removelist.copy(), linkers.copy(), adj_matrix)
1124
+ templist = linker_list.copy()
1125
+ long_ligands = False
1126
+ max_min_linker_length, min_max_linker_length = (0, 100) # The maximum value of the minimum linker length, and the minimum value of the maximum linker length. Updated later.
1127
+ linkeranchors_superlist = [] # Will contain the indices of the linker atoms that coordinate to metals
1128
+ for ii, atoms_list in reversed(list(enumerate(linker_list))): # Loop over all linker subgraphs
1129
+ linkeranchors_list = set()
1130
+ linkeranchors_atoms = set()
1131
+ sbuanchors_list = set()
1132
+ sbu_connect_list = set() # Will contain the indices of SBU subgraphs that have a connection to the current linker described by atoms_list
1133
+ """""""""
1134
+ Here, we are trying to identify what is actually a linker and what is a ligand.
1135
+ To do this, we check if something is connected to more than one SBU. Set to
1136
+ handle cases where primitive cell is small, ambiguous cases are recorded.
1137
+ """""""""
1138
+ for iii, atoms in enumerate(atoms_list): # loop over all atom indices in a linker
1139
+ connected_atoms = np.nonzero(adj_matrix[atoms, :])[1] # indices of atoms with bonds to the atom with the index atoms
1140
+ for kk, sbu_atoms_list in enumerate(initial_SBU_list): # loop over all SBU subgraphs
1141
+ for sbu_atoms in sbu_atoms_list: # Loop over SBU
1142
+ if sbu_atoms in connected_atoms: # found an SBU atom bonded to an atom in the linker defined by atoms_list
1143
+ linkeranchors_list.add(iii)
1144
+ linkeranchors_atoms.add(atoms)
1145
+ sbuanchors_list.add(sbu_atoms)
1146
+ sbu_connect_list.add(kk) # Add if unique SBUs
1147
+ min_length, max_length = linker_length(linker_subgraphlist[ii].todense(), linkeranchors_list)
1148
+ linkeranchors_superlist.append(linkeranchors_atoms)
1149
+
1150
+ if len(linkeranchors_list) >= 2: # linker, and in one ambiguous case, could be a ligand.
1151
+ if len(sbu_connect_list) >= 2: # Something that connects two SBUs is certain to be a linker
1152
+ max_min_linker_length = max(min_length, max_min_linker_length)
1153
+ min_max_linker_length = min(max_length, min_max_linker_length)
1154
+ continue
1155
+ else:
1156
+ # check number of times we cross PBC :
1157
+ # TODO: we still can fail in multidentate ligands!
1158
+ linker_cart_coords = np.array([
1159
+ at.coords() for at in [molcif.getAtom(val) for val in atoms_list]]) # Cartesian coordinates of the atoms in the linker
1160
+ linker_adjmat = np.array(linker_subgraphlist[ii].todense())
1161
+ pr_image_organic = ligand_detect(cell_v, linker_cart_coords, linker_adjmat, linkeranchors_list) # Periodic images for the organic component
1162
+ sbu_temp = linkeranchors_atoms.copy()
1163
+ sbu_temp.update({val for val in initial_SBU_list[list(sbu_connect_list)[0]]}) # Adding atoms. Not sure why the [0] is there? TODO
1164
+ sbu_temp = list(sbu_temp)
1165
+ sbu_cart_coords = np.array([
1166
+ at.coords() for at in [molcif.getAtom(val) for val in sbu_temp]])
1167
+ sbu_adjmat = slice_mat(adj_matrix.todense(), sbu_temp)
1168
+ pr_image_sbu = ligand_detect(cell_v, sbu_cart_coords, sbu_adjmat, set(range(len(linkeranchors_list)))) # Periodic images for the SBU
1169
+ if not (len(np.unique(pr_image_sbu, axis=0)) == 1 and len(np.unique(pr_image_organic, axis=0)) == 1): # linker. More than one periodic image for sbu or organic component
1170
+ max_min_linker_length = max(min_length, max_min_linker_length)
1171
+ min_max_linker_length = min(max_length, min_max_linker_length)
1172
+ tmpstr = str(name)+','+' Anchors list: '+str(sbuanchors_list) \
1173
+ + ',' + ' SBU connectlist: ' + str(sbu_connect_list) + ' set to be linker\n'
1174
+ write2file(ligandpath, "/ambiguous.txt", tmpstr)
1175
+ continue
1176
+ else: # all anchoring atoms are in the same unitcell -> ligand
1177
+ removelist.update(set(templist[ii])) # we also want to remove these ligands
1178
+ SBUlist.update(set(templist[ii])) # we also want to remove these SBUs
1179
+ linker_list.pop(ii)
1180
+ linker_subgraphlist.pop(ii)
1181
+ tmpstr = str(name)+','+' Anchors list: '+str(sbuanchors_list) \
1182
+ + ',' + ' SBU connectlist: ' + str(sbu_connect_list) + ' set to be ligand\n'
1183
+ write2file(ligandpath, "/ambiguous.txt", tmpstr)
1184
+ tmpstr = str(name)+str(ii)+','+' Anchors list: '\
1185
+ + str(sbuanchors_list) + ',' + ' SBU connectlist: ' + str(sbu_connect_list) + '\n'
1186
+ write2file(ligandpath, "/ligand.txt", tmpstr)
1187
+ else: # definite ligand
1188
+ write2file(logpath, "/%s.log" % name, "found ligand\n")
1189
+ removelist.update(set(templist[ii])) # we also want to remove these ligands
1190
+ SBUlist.update(set(templist[ii])) # we also want to remove these ligands
1191
+ linker_list.pop(ii)
1192
+ linker_subgraphlist.pop(ii)
1193
+ tmpstr = str(name)+','+' Anchors list: '+str(sbuanchors_list) \
1194
+ + ','+' SBU connectlist: '+str(sbu_connect_list)+'\n'
1195
+ write2file(ligandpath, "/ligand.txt", tmpstr)
1196
+
1197
+ tmpstr = str(name) + ", (min_max_linker_length,max_min_linker_length): " \
1198
+ + str(min_max_linker_length) + " , " + str(max_min_linker_length) + "\n"
1199
+ write2file(logpath, "/%s.log" % name, tmpstr)
1200
+ if min_max_linker_length < 3:
1201
+ write2file(linkerpath, "/short_ligands.txt", tmpstr)
1202
+ if min_max_linker_length > 2:
1203
+ # for N-C-C-N ligand ligand
1204
+ if max_min_linker_length == min_max_linker_length:
1205
+ long_ligands = True
1206
+ elif min_max_linker_length > 3:
1207
+ long_ligands = True
1208
+
1209
+ """""""""
1210
+ In the case of long linkers, add second coordination shell without further checks. In the case of short linkers, start from metal
1211
+ and grow outwards using the include_extra_shells function
1212
+ """""""""
1213
+ linker_length_list = [len(linker_val) for linker_val in linker_list]
1214
+ if len(set(linker_length_list)) != 1:
1215
+ write2file(linkerpath, "/uneven.txt", str(name)+'\n') # Linkers are different lengths.
1216
+ if not min_max_linker_length < 2: # treating the 2 atom ligands differently! Need caution
1217
+ if long_ligands:
1218
+ tmpstr = "\nStructure has LONG ligand\n\n"
1219
+ write2file(logpath, "/%s.log" % name, tmpstr)
1220
+ # Expanding the number of atoms considered to be part of the SBU
1221
+ [[SBUlist.add(val) for val in molcif.getBondedAtomsSmart(zero_first_shell)] for zero_first_shell in SBUlist.copy()] # First account for all of the carboxylic acid type linkers, add in the carbons.
1222
+ truncated_linkers = allatoms - SBUlist # Taking the difference of sets
1223
+ SBU_list, SBU_subgraphlist = get_closed_subgraph(SBUlist, truncated_linkers, adj_matrix)
1224
+ if not long_ligands:
1225
+ tmpstr = "\nStructure has SHORT ligand\n\n"
1226
+ write2file(logpath, "/%s.log" % name, tmpstr)
1227
+ SBU_list, SBU_subgraphlist = include_extra_shells(SBU_list, SBU_subgraphlist, molcif, adj_matrix)
1228
+ else:
1229
+ tmpstr = "Structure %s has extremely short ligands, check the outputs\n" % name
1230
+ write2file(ligandpath, "/ambiguous.txt", tmpstr)
1231
+ tmpstr = "Structure has extremely short ligands\n"
1232
+ write2file(logpath, "/%s.log" % name, tmpstr)
1233
+ tmpstr = "Structure has extremely short ligands\n"
1234
+ write2file(logpath, "/%s.log" % name, tmpstr)
1235
+ truncated_linkers = allatoms - removelist
1236
+ SBU_list, SBU_subgraphlist = get_closed_subgraph(removelist, truncated_linkers, adj_matrix)
1237
+ SBU_list, SBU_subgraphlist = include_extra_shells(SBU_list, SBU_subgraphlist, molcif, adj_matrix)
1238
+ SBU_list, SBU_subgraphlist = include_extra_shells(SBU_list, SBU_subgraphlist, molcif, adj_matrix)
1239
+
1240
+ """""""""
1241
+ For the cases that have a linker subgraph, do the featurization.
1242
+ """""""""
1243
+ if len(linker_subgraphlist) >= 1: # Featurize cases that did not fail.
1244
+ # try:
1245
+ descriptor_names, descriptors, lc_descriptor_names, lc_descriptors = make_MOF_SBU_RACs(SBU_list, SBU_subgraphlist, molcif, depth, name, cell_v, anc_atoms, sbupath, linkeranchors_superlist, Gval, connections_list, connections_subgraphlist)
1246
+ lig_descriptor_names, lig_descriptors = make_MOF_linker_RACs(linker_list, linker_subgraphlist, molcif, depth, name, cell_v, linkerpath, linkeranchors_superlist, Gval)
1247
+ full_names = descriptor_names+lig_descriptor_names+lc_descriptor_names #+ ECFP_names
1248
+ full_descriptors = list(descriptors)+list(lig_descriptors)+list(lc_descriptors)
1249
+ print(len(full_names), len(full_descriptors))
1250
+ # except:
1251
+ # full_names = [0]
1252
+ # full_descriptors = [0]
1253
+ elif len(linker_subgraphlist) == 1: # Only one linker identified.
1254
+ print(f'Suspicious featurization for {name}: Only one linker identified.')
1255
+ full_names = [1]
1256
+ full_descriptors = [1]
1257
+ else: # Means len(linker_subgraphlist) is zero.
1258
+ failure_str = f'Failed to featurize {name}: No linkers were identified.\n'
1259
+ full_names, full_descriptors = failure_response(path, failure_str)
1260
+ return full_names, full_descriptors
1261
+ if (len(full_names) <= 1) and (len(full_descriptors) <= 1):
1262
+ print(f'full_names is {full_names} and full_descriptors is {full_descriptors}')
1263
+ failure_str = f'Failed to featurize {name}: Only zero or one total linkers identified.\n'
1264
+ full_names, full_descriptors = failure_response(path, failure_str)
1265
+ return full_names, full_descriptors
1266
+
1267
+ # Getting bond information if requested, and writing it to a TXT file.
1268
+ if get_sbu_linker_bond_info:
1269
+ bond_information_write(linker_list, linkeranchors_superlist, adj_matrix, molcif, cell_v, path)
1270
+
1271
+ # Generating XYZ files of SBUs surrounded by linkers.
1272
+ if surrounded_sbu_file_generation:
1273
+ try:
1274
+ surrounded_sbu_gen(SBU_list, linker_list, sbupath, molcif, adj_matrix, cell_v, allatomtypes, name)
1275
+ except:
1276
+ tmpstr = "Failed to generate surrounded SBU"
1277
+ write2file(logpath, "/%s.log" % name, tmpstr)
1278
+
1279
+ if detect_1D_rod_sbu:
1280
+ detect_1D_rod(SBU_list, molcif, allatomtypes, cell_v, logpath, name)
1281
+
1282
+ return full_names, full_descriptors
1283
+
1284
+
1285
+ ##### Example of usage over a set of cif files.
1286
+ # featurization_list = []
1287
+ # import sys
1288
+ # featurization_directory = sys.argv[1]
1289
+ # for cif_file in os.listdir(featurization_directory+'/cif/'):
1290
+ # #### This first part gets the primitive cells ####
1291
+ # get_primitive(featurization_directory+'/cif/'+cif_file, featurization_directory+'/primitive/'+cif_file)
1292
+ # full_names, full_descriptors = get_MOF_descriptors(featurization_directory+'/primitive/'+cif_file,3,path=featurization_directory+'/',
1293
+ # xyzpath=featurization_directory+'/xyz/'+cif_file.replace('cif','xyz'))
1294
+ # full_names.append('filename')
1295
+ # full_descriptors.append(cif_file)
1296
+ # featurization = dict(zip(full_names, full_descriptors))
1297
+ # featurization_list.append(featurization)
1298
+ # df = pd.DataFrame(featurization_list)
1299
+ # df.to_csv('./full_featurization_frame.csv',index=False)