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.
- docs/source/conf.py +224 -0
- molSimplify/Classes/__init__.py +6 -0
- molSimplify/Classes/atom3D.py +235 -0
- molSimplify/Classes/dft_obs.py +130 -0
- molSimplify/Classes/globalvars.py +827 -0
- molSimplify/Classes/helpers.py +161 -0
- molSimplify/Classes/ligand.py +2330 -0
- molSimplify/Classes/mGUI.py +2493 -0
- molSimplify/Classes/mWidgets.py +438 -0
- molSimplify/Classes/miniGUI.py +41 -0
- molSimplify/Classes/mol2D.py +260 -0
- molSimplify/Classes/mol3D.py +5846 -0
- molSimplify/Classes/monomer3D.py +253 -0
- molSimplify/Classes/partialcharges.py +226 -0
- molSimplify/Classes/protein3D.py +1178 -0
- molSimplify/Classes/rundiag.py +151 -0
- molSimplify/Data/ML.dat +212 -0
- molSimplify/Data/MLS_FSR_for_inter.dat +23 -0
- molSimplify/Data/MLS_FSR_for_inter2.dat +23 -0
- molSimplify/Data/MLS_angle_for_click.dat +8 -0
- molSimplify/Data/MLS_angle_for_inter.dat +23 -0
- molSimplify/Data/MLS_angle_for_inter2.dat +48 -0
- molSimplify/Data/MLS_angle_for_intra.dat +10 -0
- molSimplify/Data/MLS_angle_for_intra2.dat +6 -0
- molSimplify/Data/MLS_angle_for_oa.dat +18 -0
- molSimplify/Data/ML_FSR_for_inter.dat +112 -0
- molSimplify/Data/ML_FSR_for_inter2.dat +110 -0
- molSimplify/Data/ML_bond_for_cat.dat +8 -0
- molSimplify/Data/ML_bond_for_click.dat +8 -0
- molSimplify/Data/ML_bond_for_inter.dat +48 -0
- molSimplify/Data/ML_bond_for_inter2.dat +48 -0
- molSimplify/Data/ML_bond_for_intra.dat +10 -0
- molSimplify/Data/ML_bond_for_intra2.dat +6 -0
- molSimplify/Data/ML_bond_for_oa.dat +18 -0
- molSimplify/Data/bp1.dat +21 -0
- molSimplify/Data/li.dat +3 -0
- molSimplify/Data/no.dat +2 -0
- molSimplify/Data/oct.dat +7 -0
- molSimplify/Data/pbp.dat +8 -0
- molSimplify/Data/spy.dat +6 -0
- molSimplify/Data/sqap.dat +9 -0
- molSimplify/Data/sqp.dat +5 -0
- molSimplify/Data/tbp.dat +6 -0
- molSimplify/Data/tdhd.dat +9 -0
- molSimplify/Data/thd.dat +5 -0
- molSimplify/Data/tpl.dat +4 -0
- molSimplify/Data/tpr.dat +7 -0
- molSimplify/Informatics/HFXsensitivity/__init__.py +0 -0
- molSimplify/Informatics/HFXsensitivity/measure_HFX_sensitivity_oxo_hat_reb_rel.py +443 -0
- molSimplify/Informatics/HFXsensitivity/measure_HFX_stable.py +346 -0
- molSimplify/Informatics/MOF/Linker_rotation.py +179 -0
- molSimplify/Informatics/MOF/MOF_descriptors.py +1299 -0
- molSimplify/Informatics/MOF/MOF_descriptors_alternate_functional.py +589 -0
- molSimplify/Informatics/MOF/MOF_functionalizer.py +1648 -0
- molSimplify/Informatics/MOF/PBC_functions.py +1347 -0
- molSimplify/Informatics/MOF/__init__.py +0 -0
- molSimplify/Informatics/MOF/atomic.py +267 -0
- molSimplify/Informatics/MOF/cluster_extraction.py +388 -0
- molSimplify/Informatics/MOF/fragment_MOFs_for_pormake.py +895 -0
- molSimplify/Informatics/MOF/monofunctionalized_BDC/index_information.py +10 -0
- molSimplify/Informatics/Mol2Parser.py +46 -0
- molSimplify/Informatics/RACassemble.py +408 -0
- molSimplify/Informatics/__init__.py +0 -0
- molSimplify/Informatics/active_learning/__init__.py +0 -0
- molSimplify/Informatics/active_learning/expected_improvement.py +269 -0
- molSimplify/Informatics/autocorrelation.py +1930 -0
- molSimplify/Informatics/clean_autocorrelation.py +778 -0
- molSimplify/Informatics/coulomb_analyze.py +67 -0
- molSimplify/Informatics/decoration_manager.py +193 -0
- molSimplify/Informatics/geo_analyze.py +88 -0
- molSimplify/Informatics/geometrics.py +56 -0
- molSimplify/Informatics/graph_analyze.py +163 -0
- molSimplify/Informatics/graph_racs.py +288 -0
- molSimplify/Informatics/jupyter_vis.py +172 -0
- molSimplify/Informatics/lacRACAssemble.py +2192 -0
- molSimplify/Informatics/lacRACAssemble_bisdithiolenes.py +236 -0
- molSimplify/Informatics/misc_descriptors.py +198 -0
- molSimplify/Informatics/organic_fingerprints.py +61 -0
- molSimplify/Informatics/partialcharges.py +345 -0
- molSimplify/Informatics/protein/activesite.py +53 -0
- molSimplify/Informatics/protein/pymol_add_hs.py +33 -0
- molSimplify/Informatics/rac155_geo.py +48 -0
- molSimplify/Ligands/(1_methylbenzimidazol_2_yl)pyridine.xyz +45 -0
- molSimplify/Ligands/1-4-dimethyl-1-2-3-triazole.xyz +15 -0
- molSimplify/Ligands/12crown4.mol +62 -0
- molSimplify/Ligands/Antipyrine.mol +58 -0
- molSimplify/Ligands/BPAbipy.mol +106 -0
- molSimplify/Ligands/Hpyrrole.mol +26 -0
- molSimplify/Ligands/N-quinolinylbutyramidate.xyz +31 -0
- molSimplify/Ligands/N-quinolinylmethylmethinylacetamidate.xyz +30 -0
- molSimplify/Ligands/NMe2_-1.xyz +11 -0
- molSimplify/Ligands/PCy3.mol +111 -0
- molSimplify/Ligands/PMe3.xyz +15 -0
- molSimplify/Ligands/PPh3.mol +76 -0
- molSimplify/Ligands/Propyphenazone.mol +77 -0
- molSimplify/Ligands/acac.mol +33 -0
- molSimplify/Ligands/acacen.mol +76 -0
- molSimplify/Ligands/acetate.smi +1 -0
- molSimplify/Ligands/acetate.xyz +9 -0
- molSimplify/Ligands/aceticacidbipyridine.mol +70 -0
- molSimplify/Ligands/acetonitrile.mol +17 -0
- molSimplify/Ligands/alanine.mol +30 -0
- molSimplify/Ligands/alphabetizer.py +21 -0
- molSimplify/Ligands/amine.mol +11 -0
- molSimplify/Ligands/ammonia.mol +12 -0
- molSimplify/Ligands/arginine.mol +58 -0
- molSimplify/Ligands/asparagine.mol +38 -0
- molSimplify/Ligands/aspartic_acid.mol +35 -0
- molSimplify/Ligands/azide.mol +11 -0
- molSimplify/Ligands/benzene.mol +28 -0
- molSimplify/Ligands/benzene_pi.mol +30 -0
- molSimplify/Ligands/benzenedithiol.mol +30 -0
- molSimplify/Ligands/benzenethiol.mol +30 -0
- molSimplify/Ligands/benzylisocy.mol +38 -0
- molSimplify/Ligands/bidiazine.mol +42 -0
- molSimplify/Ligands/bidiazole.mol +38 -0
- molSimplify/Ligands/bifuran.mol +38 -0
- molSimplify/Ligands/bihydrodiazine.mol +58 -0
- molSimplify/Ligands/bihydrodiazole.mol +46 -0
- molSimplify/Ligands/bihydrooxazine.mol +54 -0
- molSimplify/Ligands/bihydrooxazole.mol +42 -0
- molSimplify/Ligands/bihydrothiazine.mol +54 -0
- molSimplify/Ligands/bihydrothiazole.mol +42 -0
- molSimplify/Ligands/biimidazole.mol +38 -0
- molSimplify/Ligands/bioxazole.mol +34 -0
- molSimplify/Ligands/bipy.mol +46 -0
- molSimplify/Ligands/bipyrazine.xyz +20 -0
- molSimplify/Ligands/bipyrimidine.mol +42 -0
- molSimplify/Ligands/bipyrrole.mol +42 -0
- molSimplify/Ligands/bisnapthyridylpyridine.mol +111 -0
- molSimplify/Ligands/bithiazole.mol +34 -0
- molSimplify/Ligands/bromide.mol +7 -0
- molSimplify/Ligands/bromide.smi +1 -0
- molSimplify/Ligands/c2.mol +9 -0
- molSimplify/Ligands/caprolactone.mol +41 -0
- molSimplify/Ligands/carbonyl.mol +8 -0
- molSimplify/Ligands/carboxyl.mol +13 -0
- molSimplify/Ligands/cat.mol +30 -0
- molSimplify/Ligands/chloride.mol +7 -0
- molSimplify/Ligands/chloride.smi +1 -0
- molSimplify/Ligands/chloropyridine.mol +27 -0
- molSimplify/Ligands/co2.mol +10 -0
- molSimplify/Ligands/corrolazine.mol +72 -0
- molSimplify/Ligands/cs.mol +8 -0
- molSimplify/Ligands/cyanate.xyz +5 -0
- molSimplify/Ligands/cyanide.mol +9 -0
- molSimplify/Ligands/cyanoaceticporphyrin.mol +114 -0
- molSimplify/Ligands/cyanopyridine.mol +29 -0
- molSimplify/Ligands/cyclam.mol +81 -0
- molSimplify/Ligands/cyclen.mol +69 -0
- molSimplify/Ligands/cyclopentadienyl.mol +26 -0
- molSimplify/Ligands/cysteine.mol +32 -0
- molSimplify/Ligands/diaminomethyl.mol +19 -0
- molSimplify/Ligands/diazine.mol +25 -0
- molSimplify/Ligands/diazole.mol +23 -0
- molSimplify/Ligands/dicyanamide.mol +15 -0
- molSimplify/Ligands/dihydrofuran.mol +27 -0
- molSimplify/Ligands/dmap.xyz +35 -0
- molSimplify/Ligands/dmf.mol +28 -0
- molSimplify/Ligands/dmi.mol +41 -0
- molSimplify/Ligands/dmpe.mol +52 -0
- molSimplify/Ligands/dpmu.mol +47 -0
- molSimplify/Ligands/dppe.mol +112 -0
- molSimplify/Ligands/edta.mol +69 -0
- molSimplify/Ligands/en.mol +28 -0
- molSimplify/Ligands/ethanethiol.mol +21 -0
- molSimplify/Ligands/ethanolamine.mol +26 -0
- molSimplify/Ligands/ethbipy.mol +70 -0
- molSimplify/Ligands/ethyl.mol +19 -0
- molSimplify/Ligands/ethylamine.mol +24 -0
- molSimplify/Ligands/ethylene.mol +16 -0
- molSimplify/Ligands/ethylesteracac.mol +57 -0
- molSimplify/Ligands/fluoride.mol +7 -0
- molSimplify/Ligands/fluoride.smi +1 -0
- molSimplify/Ligands/formaldehyde.mol +12 -0
- molSimplify/Ligands/formamidate.xyz +8 -0
- molSimplify/Ligands/formate.xyz +6 -0
- molSimplify/Ligands/furan.mol +23 -0
- molSimplify/Ligands/glutamic_acid.mol +42 -0
- molSimplify/Ligands/glutamine.mol +44 -0
- molSimplify/Ligands/glycinate.mol +23 -0
- molSimplify/Ligands/glycine.mol +24 -0
- molSimplify/Ligands/h2s.mol +10 -0
- molSimplify/Ligands/helium.mol +6 -0
- molSimplify/Ligands/histidine.mol +45 -0
- molSimplify/Ligands/hmpa.mol +62 -0
- molSimplify/Ligands/hs-.mol +9 -0
- molSimplify/Ligands/hydride.mol +7 -0
- molSimplify/Ligands/hydrocarboxyacetylide.xyz +8 -0
- molSimplify/Ligands/hydrocyanide.mol +10 -0
- molSimplify/Ligands/hydrodiazine.mol +33 -0
- molSimplify/Ligands/hydrodiazole.mol +27 -0
- molSimplify/Ligands/hydrogensulfide.mol +10 -0
- molSimplify/Ligands/hydroisocyanide.mol +11 -0
- molSimplify/Ligands/hydrooxazine.mol +31 -0
- molSimplify/Ligands/hydrooxazole.mol +25 -0
- molSimplify/Ligands/hydrothiazine.mol +31 -0
- molSimplify/Ligands/hydrothiazole.mol +25 -0
- molSimplify/Ligands/hydroxyl.mol +9 -0
- molSimplify/Ligands/imidazole.mol +23 -0
- molSimplify/Ligands/imidazolidinone.mol +29 -0
- molSimplify/Ligands/imine.mol +13 -0
- molSimplify/Ligands/iminodiacetic.mol +33 -0
- molSimplify/Ligands/iodide.mol +7 -0
- molSimplify/Ligands/iodobenzene.xyz +14 -0
- molSimplify/Ligands/isoleucine.mol +48 -0
- molSimplify/Ligands/isothiocyanate.mol +11 -0
- molSimplify/Ligands/leucine.mol +48 -0
- molSimplify/Ligands/ligands.dict +257 -0
- molSimplify/Ligands/lysine.mol +54 -0
- molSimplify/Ligands/mebenzenedithiol.mol +36 -0
- molSimplify/Ligands/mebim_py.xyz +29 -0
- molSimplify/Ligands/mebim_pz.xyz +28 -0
- molSimplify/Ligands/mebipy.mol +58 -0
- molSimplify/Ligands/mecat.mol +36 -0
- molSimplify/Ligands/methanal.mol +11 -0
- molSimplify/Ligands/methanethiol.mol +15 -0
- molSimplify/Ligands/methanol.mol +16 -0
- molSimplify/Ligands/methionine.mol +44 -0
- molSimplify/Ligands/methyl.mol +13 -0
- molSimplify/Ligands/methylacetylide.xyz +8 -0
- molSimplify/Ligands/methylamine.mol +19 -0
- molSimplify/Ligands/methylazide.xyz +9 -0
- molSimplify/Ligands/methylisocy.mol +17 -0
- molSimplify/Ligands/methylpyridine.mol +33 -0
- molSimplify/Ligands/n2.mol +8 -0
- molSimplify/Ligands/n4py.xyz +51 -0
- molSimplify/Ligands/nch.mol +10 -0
- molSimplify/Ligands/nco-.mol +11 -0
- molSimplify/Ligands/nethanolamine.mol +26 -0
- molSimplify/Ligands/nitrate.mol +14 -0
- molSimplify/Ligands/nitrite.mol +11 -0
- molSimplify/Ligands/nitro.mol +11 -0
- molSimplify/Ligands/nitrobipy.mol +54 -0
- molSimplify/Ligands/nitroso.mol +8 -0
- molSimplify/Ligands/nme3.mol +30 -0
- molSimplify/Ligands/no-.mol +10 -0
- molSimplify/Ligands/no2-.mol +11 -0
- molSimplify/Ligands/noxygen.mol +8 -0
- molSimplify/Ligands/ns-.mol +10 -0
- molSimplify/Ligands/o-pyridylbenzene.xyz +23 -0
- molSimplify/Ligands/o-pyridylphenylanion.xyz +22 -0
- molSimplify/Ligands/o2-.mol +9 -0
- molSimplify/Ligands/o2.xyz +4 -0
- molSimplify/Ligands/och2.mol +12 -0
- molSimplify/Ligands/oethanolamine.mol +26 -0
- molSimplify/Ligands/ome2.mol +22 -0
- molSimplify/Ligands/ooh.xyz +5 -0
- molSimplify/Ligands/oxalate.mol +17 -0
- molSimplify/Ligands/oxalate.smi +1 -0
- molSimplify/Ligands/oxygen.mol +7 -0
- molSimplify/Ligands/pentacyanocyclopentadienide.mol +36 -0
- molSimplify/Ligands/ph2-.mol +11 -0
- molSimplify/Ligands/ph3.mol +12 -0
- molSimplify/Ligands/phen.mol +51 -0
- molSimplify/Ligands/phenacac.mol +63 -0
- molSimplify/Ligands/phenalalanine.mol +51 -0
- molSimplify/Ligands/phendione.mol +51 -0
- molSimplify/Ligands/phenphen.mol +75 -0
- molSimplify/Ligands/phenylbenzoxazole.mol +54 -0
- molSimplify/Ligands/phenylcyc.mol +99 -0
- molSimplify/Ligands/phenylenediamine.mol +37 -0
- molSimplify/Ligands/phenylisocy.mol +32 -0
- molSimplify/Ligands/phosacidbipy.mol +66 -0
- molSimplify/Ligands/phosphine.mol +13 -0
- molSimplify/Ligands/phosphorine.mol +27 -0
- molSimplify/Ligands/phosphorustrifluoride.mol +12 -0
- molSimplify/Ligands/phthalocyanine.mol +126 -0
- molSimplify/Ligands/pme3o.mol +32 -0
- molSimplify/Ligands/porphyrin.mol +82 -0
- molSimplify/Ligands/pph3o.mol +77 -0
- molSimplify/Ligands/proline.mol +39 -0
- molSimplify/Ligands/propdiol.mol +21 -0
- molSimplify/Ligands/propylene.mol +23 -0
- molSimplify/Ligands/pyridine.mol +27 -0
- molSimplify/Ligands/pyrimidone.mol +27 -0
- molSimplify/Ligands/pyrrole.mol +24 -0
- molSimplify/Ligands/quinoxalinedithiol.mol +39 -0
- molSimplify/Ligands/s2-.mol +9 -0
- molSimplify/Ligands/salen.mol +75 -0
- molSimplify/Ligands/salphen.mol +84 -0
- molSimplify/Ligands/serine.mol +32 -0
- molSimplify/Ligands/simple_ligands.dict +14 -0
- molSimplify/Ligands/sulfacidbipy.mol +63 -0
- molSimplify/Ligands/tbucat.mol +54 -0
- molSimplify/Ligands/tbuphisocy.mol +56 -0
- molSimplify/Ligands/tbutylcyclen.mol +166 -0
- molSimplify/Ligands/tbutylisocy.mol +35 -0
- molSimplify/Ligands/tbutylthiol.mol +33 -0
- molSimplify/Ligands/tcnoet.mol +43 -0
- molSimplify/Ligands/tcnoetOH.mol +45 -0
- molSimplify/Ligands/terpy.mol +65 -0
- molSimplify/Ligands/tetrahydrofuran.mol +31 -0
- molSimplify/Ligands/thiane.mol +37 -0
- molSimplify/Ligands/thiazole.mol +21 -0
- molSimplify/Ligands/thiocyanate.mol +11 -0
- molSimplify/Ligands/thiol.mol +9 -0
- molSimplify/Ligands/thiophene.mol +23 -0
- molSimplify/Ligands/thiopyridine.mol +29 -0
- molSimplify/Ligands/threonine.mol +38 -0
- molSimplify/Ligands/tpp.mol +165 -0
- molSimplify/Ligands/tricyanomethyl.mol +19 -0
- molSimplify/Ligands/trifluoromethyl.mol +13 -0
- molSimplify/Ligands/tryptophan.mol +60 -0
- molSimplify/Ligands/tyrosine.mol +53 -0
- molSimplify/Ligands/uthiol.mol +11 -0
- molSimplify/Ligands/uthiolme2.mol +23 -0
- molSimplify/Ligands/valine.mol +42 -0
- molSimplify/Ligands/water.mol +10 -0
- molSimplify/Ligands/x.mol +6 -0
- molSimplify/Scripts/__init__.py +0 -0
- molSimplify/Scripts/addtodb.py +308 -0
- molSimplify/Scripts/cellbuilder.py +1592 -0
- molSimplify/Scripts/cellbuilder_tools.py +701 -0
- molSimplify/Scripts/chains.py +342 -0
- molSimplify/Scripts/convert_2to3.py +23 -0
- molSimplify/Scripts/dbinteract.py +631 -0
- molSimplify/Scripts/distgeom.py +617 -0
- molSimplify/Scripts/findcorrelations.py +287 -0
- molSimplify/Scripts/generator.py +267 -0
- molSimplify/Scripts/geometry.py +1224 -0
- molSimplify/Scripts/grabguivars.py +845 -0
- molSimplify/Scripts/in_b3lyp_usetc.py +141 -0
- molSimplify/Scripts/inparse.py +1673 -0
- molSimplify/Scripts/io.py +1149 -0
- molSimplify/Scripts/isomers.py +415 -0
- molSimplify/Scripts/jobgen.py +247 -0
- molSimplify/Scripts/krr_prep.py +1262 -0
- molSimplify/Scripts/molSimplify_io.py +18 -0
- molSimplify/Scripts/molden2psi4wfn.py +166 -0
- molSimplify/Scripts/namegen.py +32 -0
- molSimplify/Scripts/nn_prep.py +561 -0
- molSimplify/Scripts/oct_check_mols.py +782 -0
- molSimplify/Scripts/periodic_QE.py +97 -0
- molSimplify/Scripts/postmold.py +304 -0
- molSimplify/Scripts/postmwfn.py +709 -0
- molSimplify/Scripts/postparse.py +488 -0
- molSimplify/Scripts/postproc.py +139 -0
- molSimplify/Scripts/qcgen.py +1450 -0
- molSimplify/Scripts/rmsd.py +489 -0
- molSimplify/Scripts/rungen.py +670 -0
- molSimplify/Scripts/structgen.py +3040 -0
- molSimplify/Scripts/tf_nn_prep.py +894 -0
- molSimplify/Scripts/tsgen.py +295 -0
- molSimplify/Scripts/uq_calibration.py +69 -0
- molSimplify/__init__.py +0 -0
- molSimplify/__main__.py +197 -0
- molSimplify/icons/chemdb.png +0 -0
- molSimplify/icons/hjklogo.png +0 -0
- molSimplify/icons/icon.png +0 -0
- molSimplify/icons/logo.png +0 -0
- molSimplify/icons/logo_old.png +0 -0
- molSimplify/icons/petachem.png +0 -0
- molSimplify/icons/petachem2.png +0 -0
- molSimplify/icons/petachem_full.png +0 -0
- molSimplify/icons/pythonlogo.png +0 -0
- molSimplify/icons/sge copy.png +0 -0
- molSimplify/icons/sge.png +0 -0
- molSimplify/icons/slurm.png +0 -0
- molSimplify/icons/wft1.png +0 -0
- molSimplify/icons/wft2.png +0 -0
- molSimplify/icons/wft3.png +0 -0
- molSimplify/ml/__init__.py +0 -0
- molSimplify/ml/kernels.py +36 -0
- molSimplify/ml/layers.py +29 -0
- molSimplify/molscontrol/__init__.py +14 -0
- molSimplify/molscontrol/_version.py +521 -0
- molSimplify/molscontrol/clf_tools.py +144 -0
- molSimplify/molscontrol/data/README.md +21 -0
- molSimplify/molscontrol/data/look_and_say.dat +15 -0
- molSimplify/molscontrol/dynamic_classifier.py +514 -0
- molSimplify/molscontrol/io_tools.py +363 -0
- molSimplify/molscontrol/molscontrol.py +49 -0
- molSimplify/molscontrol/terachem/jobscript_control.sh +31 -0
- molSimplify/molscontrol/terachem/terachem_input +22 -0
- molSimplify/python_krr/X_train_TS.csv +535 -0
- molSimplify/python_krr/__init__.py +0 -0
- molSimplify/python_krr/hat2_X_mean_std.csv +3 -0
- molSimplify/python_krr/hat2_feature_names.csv +1 -0
- molSimplify/python_krr/hat2_y_mean_std.csv +2 -0
- molSimplify/python_krr/hat_X_mean_std.csv +6 -0
- molSimplify/python_krr/hat_feature_names.csv +1 -0
- molSimplify/python_krr/hat_krr_X_train.csv +5205 -0
- molSimplify/python_krr/hat_krr_dual_coef.csv +1 -0
- molSimplify/python_krr/hat_y_mean_std.csv +2 -0
- molSimplify/python_krr/sklearn_models.py +34 -0
- molSimplify/python_krr/y_train_TS.csv +535 -0
- molSimplify/python_nn/ANN.py +198 -0
- molSimplify/python_nn/__init__.py +0 -0
- molSimplify/python_nn/clf_analysis_tool.py +125 -0
- molSimplify/python_nn/dictionary_toolbox.py +49 -0
- molSimplify/python_nn/ensemble_test.py +309 -0
- molSimplify/python_nn/hs_center.csv +26 -0
- molSimplify/python_nn/hs_scale.csv +26 -0
- molSimplify/python_nn/ls_center.csv +26 -0
- molSimplify/python_nn/ls_scale.csv +26 -0
- molSimplify/python_nn/ms_hs_b1.csv +50 -0
- molSimplify/python_nn/ms_hs_b2.csv +50 -0
- molSimplify/python_nn/ms_hs_b3.csv +1 -0
- molSimplify/python_nn/ms_hs_w1.csv +50 -0
- molSimplify/python_nn/ms_hs_w2.csv +50 -0
- molSimplify/python_nn/ms_hs_w3.csv +1 -0
- molSimplify/python_nn/ms_ls_b1.csv +50 -0
- molSimplify/python_nn/ms_ls_b2.csv +50 -0
- molSimplify/python_nn/ms_ls_b3.csv +1 -0
- molSimplify/python_nn/ms_ls_w1.csv +50 -0
- molSimplify/python_nn/ms_ls_w2.csv +50 -0
- molSimplify/python_nn/ms_ls_w3.csv +1 -0
- molSimplify/python_nn/ms_slope_b1.csv +50 -0
- molSimplify/python_nn/ms_slope_b2.csv +50 -0
- molSimplify/python_nn/ms_slope_b3.csv +1 -0
- molSimplify/python_nn/ms_slope_w1.csv +50 -0
- molSimplify/python_nn/ms_slope_w2.csv +50 -0
- molSimplify/python_nn/ms_slope_w3.csv +1 -0
- molSimplify/python_nn/ms_split_b1.csv +50 -0
- molSimplify/python_nn/ms_split_b2.csv +50 -0
- molSimplify/python_nn/ms_split_b3.csv +1 -0
- molSimplify/python_nn/ms_split_w1.csv +50 -0
- molSimplify/python_nn/ms_split_w2.csv +50 -0
- molSimplify/python_nn/ms_split_w3.csv +1 -0
- molSimplify/python_nn/slope_center.csv +25 -0
- molSimplify/python_nn/slope_scale.csv +25 -0
- molSimplify/python_nn/split_center.csv +26 -0
- molSimplify/python_nn/split_scale.csv +26 -0
- molSimplify/python_nn/tf_ANN.py +762 -0
- molSimplify/python_nn/train_data.csv +1211 -0
- molSimplify/tf_nn/__init__.py +0 -0
- molSimplify/tf_nn/geo_static_clf/geo_static_clf_model.h5 +0 -0
- molSimplify/tf_nn/geo_static_clf/geo_static_clf_train_name.csv +1591 -0
- molSimplify/tf_nn/geo_static_clf/geo_static_clf_train_x.csv +2790 -0
- molSimplify/tf_nn/geo_static_clf/geo_static_clf_train_y.csv +2790 -0
- molSimplify/tf_nn/geo_static_clf/geo_static_clf_vars.csv +154 -0
- molSimplify/tf_nn/geos/hs_ii_bl_x.csv +1577 -0
- molSimplify/tf_nn/geos/hs_ii_bl_y.csv +1577 -0
- molSimplify/tf_nn/geos/hs_ii_model.h5 +0 -0
- molSimplify/tf_nn/geos/hs_ii_model.json +1 -0
- molSimplify/tf_nn/geos/hs_ii_vars.csv +154 -0
- molSimplify/tf_nn/geos/hs_iii_bl_x.csv +1659 -0
- molSimplify/tf_nn/geos/hs_iii_bl_y.csv +1659 -0
- molSimplify/tf_nn/geos/hs_iii_model.h5 +0 -0
- molSimplify/tf_nn/geos/hs_iii_model.json +1 -0
- molSimplify/tf_nn/geos/hs_iii_vars.csv +154 -0
- molSimplify/tf_nn/geos/ls_ii_bl_x.csv +1374 -0
- molSimplify/tf_nn/geos/ls_ii_bl_y.csv +1374 -0
- molSimplify/tf_nn/geos/ls_ii_model.h5 +0 -0
- molSimplify/tf_nn/geos/ls_ii_model.json +1 -0
- molSimplify/tf_nn/geos/ls_ii_vars.csv +154 -0
- molSimplify/tf_nn/geos/ls_iii_bl_x.csv +1364 -0
- molSimplify/tf_nn/geos/ls_iii_bl_y.csv +1364 -0
- molSimplify/tf_nn/geos/ls_iii_model.h5 +0 -0
- molSimplify/tf_nn/geos/ls_iii_model.json +1 -0
- molSimplify/tf_nn/geos/ls_iii_vars.csv +154 -0
- molSimplify/tf_nn/homolumo/gap_model.h5 +0 -0
- molSimplify/tf_nn/homolumo/gap_model.json +1 -0
- molSimplify/tf_nn/homolumo/gap_test_names.csv +175 -0
- molSimplify/tf_nn/homolumo/gap_test_x.csv +176 -0
- molSimplify/tf_nn/homolumo/gap_test_y.csv +176 -0
- molSimplify/tf_nn/homolumo/gap_train_names.csv +699 -0
- molSimplify/tf_nn/homolumo/gap_train_x.csv +700 -0
- molSimplify/tf_nn/homolumo/gap_train_y.csv +700 -0
- molSimplify/tf_nn/homolumo/gap_vars.csv +153 -0
- molSimplify/tf_nn/homolumo/homo_model.h5 +0 -0
- molSimplify/tf_nn/homolumo/homo_model.json +126 -0
- molSimplify/tf_nn/homolumo/homo_test_names.csv +175 -0
- molSimplify/tf_nn/homolumo/homo_test_x.csv +176 -0
- molSimplify/tf_nn/homolumo/homo_test_y.csv +176 -0
- molSimplify/tf_nn/homolumo/homo_train_names.csv +699 -0
- molSimplify/tf_nn/homolumo/homo_train_x.csv +700 -0
- molSimplify/tf_nn/homolumo/homo_train_y.csv +700 -0
- molSimplify/tf_nn/homolumo/homo_vars.csv +153 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_info.json +7 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_model.h5 +0 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_model.json +1 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_test_names.csv +143 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_test_x.csv +144 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_test_y.csv +144 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_train_names.csv +513 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_train_x.csv +514 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_train_y.csv +514 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_val_names.csv +143 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_val_x.csv +58 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_val_y.csv +58 -0
- molSimplify/tf_nn/oxoandhomo/homo_empty_vars.csv +155 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_info.json +7 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_model.h5 +0 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_model.json +1 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_test_names.csv +143 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_test_x.csv +144 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_test_y.csv +144 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_train_names.csv +513 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_train_x.csv +514 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_train_y.csv +514 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_val_names.csv +143 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_val_x.csv +58 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_val_y.csv +58 -0
- molSimplify/tf_nn/oxoandhomo/oxo20_vars.csv +154 -0
- molSimplify/tf_nn/oxocatalysis/hat_model.h5 +0 -0
- molSimplify/tf_nn/oxocatalysis/hat_model.json +1 -0
- molSimplify/tf_nn/oxocatalysis/hat_test_names.csv +419 -0
- molSimplify/tf_nn/oxocatalysis/hat_test_x.csv +420 -0
- molSimplify/tf_nn/oxocatalysis/hat_test_y.csv +420 -0
- molSimplify/tf_nn/oxocatalysis/hat_train_names.csv +1507 -0
- molSimplify/tf_nn/oxocatalysis/hat_train_x.csv +1508 -0
- molSimplify/tf_nn/oxocatalysis/hat_train_y.csv +1508 -0
- molSimplify/tf_nn/oxocatalysis/hat_val_x.csv +169 -0
- molSimplify/tf_nn/oxocatalysis/hat_val_y.csv +169 -0
- molSimplify/tf_nn/oxocatalysis/hat_vars.csv +162 -0
- molSimplify/tf_nn/oxocatalysis/oxo_model.h5 +0 -0
- molSimplify/tf_nn/oxocatalysis/oxo_model.json +1 -0
- molSimplify/tf_nn/oxocatalysis/oxo_test_names.csv +527 -0
- molSimplify/tf_nn/oxocatalysis/oxo_test_x.csv +528 -0
- molSimplify/tf_nn/oxocatalysis/oxo_test_y.csv +528 -0
- molSimplify/tf_nn/oxocatalysis/oxo_train_names.csv +1897 -0
- molSimplify/tf_nn/oxocatalysis/oxo_train_x.csv +1898 -0
- molSimplify/tf_nn/oxocatalysis/oxo_train_y.csv +1898 -0
- molSimplify/tf_nn/oxocatalysis/oxo_val_x.csv +212 -0
- molSimplify/tf_nn/oxocatalysis/oxo_val_y.csv +212 -0
- molSimplify/tf_nn/oxocatalysis/oxo_vars.csv +162 -0
- molSimplify/tf_nn/rescaling_data/gap_mean_x.csv +153 -0
- molSimplify/tf_nn/rescaling_data/gap_mean_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/gap_var_x.csv +153 -0
- molSimplify/tf_nn/rescaling_data/gap_var_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/geo_static_clf_mean_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/geo_static_clf_mean_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/geo_static_clf_var_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/geo_static_clf_var_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/hat_mean_x.csv +162 -0
- molSimplify/tf_nn/rescaling_data/hat_mean_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/hat_var_x.csv +162 -0
- molSimplify/tf_nn/rescaling_data/hat_var_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/homo_empty_mean_x.csv +155 -0
- molSimplify/tf_nn/rescaling_data/homo_empty_mean_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/homo_empty_var_x.csv +155 -0
- molSimplify/tf_nn/rescaling_data/homo_empty_var_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/homo_mean_x.csv +153 -0
- molSimplify/tf_nn/rescaling_data/homo_mean_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/homo_var_x.csv +153 -0
- molSimplify/tf_nn/rescaling_data/homo_var_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/hs_ii_mean_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/hs_ii_mean_y.csv +3 -0
- molSimplify/tf_nn/rescaling_data/hs_ii_var_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/hs_ii_var_y.csv +3 -0
- molSimplify/tf_nn/rescaling_data/hs_iii_mean_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/hs_iii_mean_y.csv +3 -0
- molSimplify/tf_nn/rescaling_data/hs_iii_var_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/hs_iii_var_y.csv +3 -0
- molSimplify/tf_nn/rescaling_data/ls_ii_mean_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/ls_ii_mean_y.csv +3 -0
- molSimplify/tf_nn/rescaling_data/ls_ii_var_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/ls_ii_var_y.csv +3 -0
- molSimplify/tf_nn/rescaling_data/ls_iii_mean_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/ls_iii_mean_y.csv +3 -0
- molSimplify/tf_nn/rescaling_data/ls_iii_var_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/ls_iii_var_y.csv +3 -0
- molSimplify/tf_nn/rescaling_data/oxo20_mean_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/oxo20_mean_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/oxo20_var_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/oxo20_var_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/oxo_mean_x.csv +162 -0
- molSimplify/tf_nn/rescaling_data/oxo_mean_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/oxo_var_x.csv +162 -0
- molSimplify/tf_nn/rescaling_data/oxo_var_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/sc_static_clf_mean_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/sc_static_clf_mean_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/sc_static_clf_var_x.csv +154 -0
- molSimplify/tf_nn/rescaling_data/sc_static_clf_var_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/split_mean_x.csv +155 -0
- molSimplify/tf_nn/rescaling_data/split_mean_y.csv +1 -0
- molSimplify/tf_nn/rescaling_data/split_var_x.csv +155 -0
- molSimplify/tf_nn/rescaling_data/split_var_y.csv +1 -0
- molSimplify/tf_nn/sc_static_clf/sc_static_clf_model.h5 +0 -0
- molSimplify/tf_nn/sc_static_clf/sc_static_clf_train_name.csv +1591 -0
- molSimplify/tf_nn/sc_static_clf/sc_static_clf_train_x.csv +1592 -0
- molSimplify/tf_nn/sc_static_clf/sc_static_clf_train_y.csv +1592 -0
- molSimplify/tf_nn/sc_static_clf/sc_static_clf_vars.csv +154 -0
- molSimplify/tf_nn/split/split_model.h5 +0 -0
- molSimplify/tf_nn/split/split_model.json +1 -0
- molSimplify/tf_nn/split/split_vars.csv +155 -0
- molSimplify/tf_nn/split/split_x.csv +1902 -0
- molSimplify/tf_nn/split/split_y.csv +1902 -0
- molSimplify/tf_nn/split/train_names.csv +1901 -0
- molSimplify/utils/__init__.py +0 -0
- molSimplify/utils/decorators.py +16 -0
- molSimplify/utils/metaclasses.py +12 -0
- molSimplify/utils/tensorflow.py +23 -0
- molSimplify/utils/timer.py +16 -0
- molSimplify-1.7.4.dist-info/LICENSE +674 -0
- molSimplify-1.7.4.dist-info/METADATA +821 -0
- molSimplify-1.7.4.dist-info/RECORD +651 -0
- molSimplify-1.7.4.dist-info/WHEEL +5 -0
- molSimplify-1.7.4.dist-info/entry_points.txt +3 -0
- molSimplify-1.7.4.dist-info/top_level.txt +4 -0
- tests/generateTests.py +122 -0
- tests/helperFuncs.py +658 -0
- tests/informatics/test_MOF_descriptors.py +128 -0
- tests/informatics/test_active_learning.py +113 -0
- tests/informatics/test_coulomb_analyze.py +24 -0
- tests/informatics/test_graph_racs.py +193 -0
- tests/ml/test_kernels.py +20 -0
- tests/ml/test_layers.py +47 -0
- tests/runtest.py +10 -0
- tests/test_Mol2D.py +128 -0
- tests/test_basic_imports.py +62 -0
- tests/test_bidentate.py +25 -0
- tests/test_cli.py +20 -0
- tests/test_distgeom.py +106 -0
- tests/test_example_1.py +29 -0
- tests/test_example_3.py +31 -0
- tests/test_example_5.py +43 -0
- tests/test_example_7.py +28 -0
- tests/test_example_8.py +15 -0
- tests/test_example_tbp.py +15 -0
- tests/test_ff_xtb.py +111 -0
- tests/test_geocheck_oct.py +26 -0
- tests/test_geocheck_one_empty.py +15 -0
- tests/test_geometry.py +44 -0
- tests/test_inparse.py +76 -0
- tests/test_io.py +84 -0
- tests/test_jobgen.py +84 -0
- tests/test_joption_pythonic.py +27 -0
- tests/test_ligand_assign.py +58 -0
- tests/test_ligand_assign_consistent.py +60 -0
- tests/test_ligand_class.py +26 -0
- tests/test_ligand_from_mol_file.py +35 -0
- tests/test_ligands.py +86 -0
- tests/test_mol3D.py +337 -0
- tests/test_molcas_caspt2.py +15 -0
- tests/test_molcas_casscf.py +15 -0
- tests/test_old_ANNs.py +68 -0
- tests/test_orca_ccsdt.py +15 -0
- tests/test_orca_dft.py +15 -0
- tests/test_qcgen.py +50 -0
- tests/test_racs.py +124 -0
- tests/test_rmsd.py +68 -0
- tests/test_structgen_functions.py +198 -0
- tests/test_tetrahedral.py +29 -0
- tests/test_tutorial_10_part_one.py +16 -0
- tests/test_tutorial_10_part_two.py +15 -0
- tests/test_tutorial_2.py +11 -0
- tests/test_tutorial_3.py +15 -0
- tests/test_tutorial_4.py +57 -0
- tests/test_tutorial_6.py +10 -0
- tests/test_tutorial_8.py +29 -0
- tests/test_tutorial_9_part_one.py +15 -0
- tests/test_tutorial_9_part_two.py +15 -0
- tests/test_tutorial_qm9_part_one.py +6 -0
- tests/testresources/refs/racs/generate_references.py +85 -0
- workflows/NandyJACSAu2022/bridge_functionalizer.py +253 -0
- workflows/NandyJACSAu2022/frag_functionalizer.py +242 -0
- workflows/NandyJACSAu2022/fragment_classes.py +586 -0
- 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)
|