From e53af751d6db3881c6b50b70360d66a6e55e0229 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Thu, 14 Nov 2024 19:02:48 -0500 Subject: [PATCH 01/19] structgen upload... scary hope this isn't awful --- molSimplify/Scripts/structgen.py | 152 ++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 3 deletions(-) diff --git a/molSimplify/Scripts/structgen.py b/molSimplify/Scripts/structgen.py index 1d516e84..691e926a 100644 --- a/molSimplify/Scripts/structgen.py +++ b/molSimplify/Scripts/structgen.py @@ -12,6 +12,7 @@ from openbabel import openbabel # version 3 style import except ImportError: import openbabel # fallback to version 2 +from openbabel import pybel import random import itertools import numpy as np @@ -2306,6 +2307,7 @@ def mcomplex(args: Namespace, ligs: List[str], ligoc: List[int] emsg = '' complex3D: List[mol3D] = [] occs0 = [] # occurrences of each ligand + complex2D = [] toccs = 0 # total occurrence count (number of ligands) smilesligs = 0 # count how many smiles strings cats0: List[List[Union[int, str]]] = [] # connection atoms for ligands @@ -2507,6 +2509,8 @@ def mcomplex(args: Namespace, ligs: List[str], ligoc: List[int] lig = decorate_ligand( lig, args.decoration[i], args.decoration_index[i], args.debug) lig.convert2mol3D() + + # initialize ligand lig3D, rempi, ligpiatoms = init_ligand(args, lig, tcats, keepHs, i) if emsg: @@ -2710,16 +2714,34 @@ def mcomplex(args: Namespace, ligs: List[str], ligoc: List[int] auxm = mol3D() auxm.copymol3D(lig3D) complex3D.append(auxm) + + lig3D_copy = mol3D() + lig3D_copy.copymol3D(lig3D) + lig3D_copy.populateBOMatrix(bonddict=True) + lig2D = lig3D_copy.mol3D_to_networkx() + complex2D.append(lig2D) + if 'a' not in lig.ffopt.lower(): for latdix in range(0, lig3D.natoms): if args.debug: print(('a is not ff.lower, so adding atom: ' + str(latdix+core3D.natoms) + ' to freeze')) frozenats.append(latdix+core3D.natoms) + + + + # combine molecules + if len(core3D.atoms) == 1: + core3D_copy = mol3D() + core3D_copy.copymol3D(core3D) + core3D_copy = core3D_copy.roland_combine(lig3D_copy, catoms) + + # combine molecules core3D = core3D.combine(lig3D) core3D.convert2OBMol() core3D.convert2mol3D() + # remove dummy cm atom if requested if rempi: # remove the fictitious center atom, for aromatic-bonding ligands like benzene @@ -2792,6 +2814,8 @@ def mcomplex(args: Namespace, ligs: List[str], ligoc: List[int] core3D.writexyz('complex_after_final_ff.xyz') # core3D,enc = ffopt(args.ff,core3D,connected,1,frozenats,freezeangles,MLoptbds,'Adaptive',args.debug) + core3D.bo_dict = core3D_copy.bo_dict + return core3D, complex3D, emsg, this_diag, subcatoms_ext, mligcatoms_ext @@ -2924,7 +2948,7 @@ def generate_report(args: Namespace, ligands: List[str], ligoc: List[int] def structgen(args: Namespace, rootdir: str, ligands: List[str], ligoc: List[int], - sernum: int, write_files: bool = True) -> Tuple[List[str], str, run_diag]: + sernum: int, write_files: bool = True, smart_generation: bool = True) -> Tuple[List[str], str, run_diag]: """Main structure generation routine - multiple structures Parameters @@ -3015,7 +3039,129 @@ def structgen(args: Namespace, rootdir: str, ligands: List[str], ligoc: List[int # write xyz file if (not args.reportonly) and (write_files): - core3D.writexyz(fname, no_tabs=args.no_tabs) + core3D.writexyz(fname) + core3D.writemol2(fname) + + if smart_generation == True: + # optimize + metal_ind = core3D.findMetal()[0] + freeze_inds = [] + for bond in core3D.bo_dict: + if metal_ind in bond: + freeze_inds.append(bond[0]+1) + freeze_inds.append(bond[1]+1) + freeze_inds = list(set(list(freeze_inds))) + + obConversion = openbabel.OBConversion() + OBMol = openbabel.OBMol() + constraints = openbabel.OBFFConstraints() + obConversion.SetInAndOutFormats("mol2", "mol2") + obConversion.ReadString(OBMol, core3D.writemol2('',writestring = True)) + for atom in freeze_inds: + constraints.AddAtomConstraint(atom) + ff = pybel._forcefields["uff"] + success = ff.Setup(OBMol, constraints) + ff.SetConstraints(constraints) + if success: + ff.ConjugateGradients(10000) + ff.GetCoordinates(OBMol) + obConversion.WriteFile(OBMol,fname+'BABEL.mol2') + obConversion.SetOutFormat("xyz") + obConversion.WriteFile(OBMol,fname+'BABEL.xyz') + + # check if bad + mol = mol3D() + mol.readfrommol2(fname+'BABEL.mol2') + overlap, mind = mol.sanitycheck(silence = True) + if overlap: + mind = 1000 + errors_dict = {} + for ii, atom1 in enumerate(mol.atoms): + for jj, atom0 in enumerate(mol.atoms): + if jj > ii: + if atom1.ismetal() or atom0.ismetal(): + cutoff = 0.6 + elif (atom0.sym in ['N', 'O'] and atom1.sym == 'H') or (atom1.sym in ['N', 'O'] and atom0.sym == 'H'): + cutoff = 0.6 + else: + cutoff = 0.65 + if distance(atom1.coords(), atom0.coords()) < cutoff * (atom1.rad + atom0.rad): + norm = distance( + atom1.coords(), atom0.coords())/(atom1.rad+atom0.rad) + errors_dict.update( + {atom1.sym + str(ii)+'-'+atom0.sym+str(jj)+'_normdist': norm}) + if distance(atom1.coords(), atom0.coords()) < mind: + mind = distance(atom1.coords(), atom0.coords()) + if mind == 0.0: + # move atom0 over a little bit + atom0.setcoords(np.array(atom1.coords())+0.02) + obConversion.SetInAndOutFormats("mol2", "mol2") + OBMol = openbabel.OBMol() + obConversion.ReadString(OBMol, mol.writemol2('',writestring = True)) + + ff = pybel._forcefields["gaff"] + success = ff.Setup(OBMol, constraints) + ff.SetConstraints(constraints) + if success: + ff.ConjugateGradients(10000) + ff.GetCoordinates(OBMol) + ff = pybel._forcefields["uff"] + success = ff.Setup(OBMol, constraints) + ff.SetConstraints(constraints) + if success: + ff.ConjugateGradients(10000) + ff.GetCoordinates(OBMol) + + + obConversion.SetOutFormat("mol2") + obConversion.WriteFile(OBMol,fname+'BABEL.mol2') + obConversion.SetOutFormat("xyz") + obConversion.WriteFile(OBMol,fname+'BABEL.xyz') + + # check if overextended H: + mol = mol3D() + mol.readfrommol2(fname+'BABEL.mol2') + changed = False + for bond in mol.bo_dict: + atom0 = mol.atoms[bond[0]] + atom1 = mol.atoms[bond[1]] + dist = -100000000000 + if atom0.sym == 'C' and atom1.sym == 'H': + dist = atom0.distance(atom1) + L1 = np.array(tuple(atom0.coords())) + L2 = np.array(tuple(atom1.coords())) + if dist > 1.15: + vector = L1 - L2 + required_dist = dist - 1.15 + new_point = move_point(atom1.coords(), vector, required_dist) + atom1.setcoords(new_point) + changed = True + elif atom0.sym == 'H' and atom1.sym == 'C': + dist = atom0.distance(atom1) + if dist > 1.15: + L1 = np.array(tuple(atom0.coords())) + L2 = np.array(tuple(atom1.coords())) + vector = L2 - L1 + required_dist = dist - 1.15 + new_point = move_point(atom0.coords(), vector, required_dist) + atom0.setcoords(new_point) + changed = True + if changed: + mol.writemol2(fname+'BABEL.mol2') + obConversion = openbabel.OBConversion() + OBMol = openbabel.OBMol() + obConversion.SetInAndOutFormats("mol2", "mol2") + obConversion.ReadFile(OBMol, fname+'BABEL.mol2') + ff = pybel._forcefields["uff"] + success = ff.Setup(OBMol, constraints) + ff.SetConstraints(constraints) + if success: + ff.ConjugateGradients(10000) + ff.GetCoordinates(OBMol) + obConversion.WriteFile(OBMol,fname+'BABEL.mol2') + obConversion.SetOutFormat("xyz") + obConversion.WriteFile(OBMol,fname+'BABEL.xyz') + strfiles.append(fname) if write_files: # write report file @@ -3037,4 +3183,4 @@ def structgen(args: Namespace, rootdir: str, ligands: List[str], ligoc: List[int args.gui.app.processEvents() print(('\nIn folder '+rootdir+' generated 1 structure!')) - return strfiles, emsg, this_diag + return strfiles, emsg, this_diag \ No newline at end of file From dc29fa736d5e179835c50dc2a54be364b279a036 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Thu, 14 Nov 2024 19:03:53 -0500 Subject: [PATCH 02/19] Update structgen.py added move_point compatibility --- molSimplify/Scripts/structgen.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/molSimplify/Scripts/structgen.py b/molSimplify/Scripts/structgen.py index 691e926a..545592ff 100644 --- a/molSimplify/Scripts/structgen.py +++ b/molSimplify/Scripts/structgen.py @@ -26,6 +26,7 @@ getPointu, kabsch, midpt, + move_point, norm, PointTranslateSph, reflect_through_plane, @@ -3183,4 +3184,4 @@ def structgen(args: Namespace, rootdir: str, ligands: List[str], ligoc: List[int args.gui.app.processEvents() print(('\nIn folder '+rootdir+' generated 1 structure!')) - return strfiles, emsg, this_diag \ No newline at end of file + return strfiles, emsg, this_diag From 249141fe01a369387ad558a1bc7d4461bd44b0b4 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Thu, 14 Nov 2024 19:08:29 -0500 Subject: [PATCH 03/19] Update structgen.py no_tabs brought back --- molSimplify/Scripts/structgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/molSimplify/Scripts/structgen.py b/molSimplify/Scripts/structgen.py index 545592ff..fe4532a9 100644 --- a/molSimplify/Scripts/structgen.py +++ b/molSimplify/Scripts/structgen.py @@ -3040,7 +3040,7 @@ def structgen(args: Namespace, rootdir: str, ligands: List[str], ligoc: List[int # write xyz file if (not args.reportonly) and (write_files): - core3D.writexyz(fname) + core3D.writexyz(fname, no_tabs=args.no_tabs) core3D.writemol2(fname) if smart_generation == True: From efaa28cc2b78a133158ea73eaac853634925f68d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 00:14:18 +0000 Subject: [PATCH 04/19] [pre-commit.ci] auto fixes from pre-commit hooks --- molSimplify/Scripts/structgen.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/molSimplify/Scripts/structgen.py b/molSimplify/Scripts/structgen.py index fe4532a9..79c49036 100644 --- a/molSimplify/Scripts/structgen.py +++ b/molSimplify/Scripts/structgen.py @@ -2718,7 +2718,7 @@ def mcomplex(args: Namespace, ligs: List[str], ligoc: List[int] lig3D_copy = mol3D() lig3D_copy.copymol3D(lig3D) - lig3D_copy.populateBOMatrix(bonddict=True) + lig3D_copy.populateBOMatrix(bonddict=True) lig2D = lig3D_copy.mol3D_to_networkx() complex2D.append(lig2D) @@ -2730,13 +2730,13 @@ def mcomplex(args: Namespace, ligs: List[str], ligoc: List[int] frozenats.append(latdix+core3D.natoms) - + # combine molecules if len(core3D.atoms) == 1: core3D_copy = mol3D() core3D_copy.copymol3D(core3D) core3D_copy = core3D_copy.roland_combine(lig3D_copy, catoms) - + # combine molecules core3D = core3D.combine(lig3D) @@ -3042,7 +3042,7 @@ def structgen(args: Namespace, rootdir: str, ligands: List[str], ligoc: List[int if (not args.reportonly) and (write_files): core3D.writexyz(fname, no_tabs=args.no_tabs) core3D.writemol2(fname) - + if smart_generation == True: # optimize metal_ind = core3D.findMetal()[0] @@ -3112,7 +3112,7 @@ def structgen(args: Namespace, rootdir: str, ligands: List[str], ligoc: List[int if success: ff.ConjugateGradients(10000) ff.GetCoordinates(OBMol) - + obConversion.SetOutFormat("mol2") obConversion.WriteFile(OBMol,fname+'BABEL.mol2') From d172d305d6962d81357962a3bd3b17535e902a35 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Thu, 14 Nov 2024 19:15:45 -0500 Subject: [PATCH 05/19] Update structgen.py fixed trailing whitespace From 2646cb6eb4f4f94ed189ece936e60124a8a2ef92 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Thu, 14 Nov 2024 19:22:00 -0500 Subject: [PATCH 06/19] Update mol3D.py needed for my structgen changes --- molSimplify/Classes/mol3D.py | 93 ++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/molSimplify/Classes/mol3D.py b/molSimplify/Classes/mol3D.py index bcf76db9..bc26571f 100644 --- a/molSimplify/Classes/mol3D.py +++ b/molSimplify/Classes/mol3D.py @@ -6470,3 +6470,96 @@ def get_molecular_mass(self): self.mass = mol_mass return mol_mass + + def mol3D_to_networkx(self,get_symbols:bool=True,get_bond_order:bool=True,get_bond_distance:bool=False): + g = nx.Graph() + # get every index of atoms in mol3D object + for atom_ind in range(0,self.natoms): + # set each atom as a node in the graph, and add symbol information if wanted + data={} + if get_symbols: + data['Symbol']=self.getAtom(atom_ind).symbol() + data['atom3D']=self.getAtom(atom_ind) + g.add_node(atom_ind,**data) + # get every bond in mol3D object + bond_info=self.bo_dict + for bond in bond_info: + # set each bond as an edge in the graph, and add symbol information if wanted + data={} + if get_bond_order: + data['bond_order']=bond_info[bond] + if get_bond_distance: + distance=self.getAtom(bond[0]).distance(self.getAtom(bond[1])) + data['bond_distance']=distance + g.add_edge(bond[0],bond[1],**data) + return g + + def roland_combine(self, mol, catoms, bond_to_add=[], dirty=False): + """ + Combines two molecules. Each atom in the second molecule + is appended to the first while preserving orders. Assumes + operation with a given mol3D instance, when handed a second mol3D instance. + + Parameters + ---------- + mol : mol3D + mol3D class instance containing molecule to be added. + bond_to_add : list, optional + List of tuples (ind1,ind2,order) bonds to add. Default is empty. + dirty : bool, optional + Add atoms without worrying about bond orders. Default is False. + + Returns + ------- + cmol : mol3D + New mol3D class containing the two molecules combined. + """ + + cmol = self + bo_dict = cmol.bo_dict + + print('lig_dict') + print(mol.bo_dict) + + if cmol.bo_dict == False: + # only central metal + bo_dict = {} + new_bo_dict = copy.deepcopy(bo_dict) + + # add ligand connections + for bo in mol.bo_dict: + ind1 = bo[0] + len(cmol.atoms) + ind2 = bo[1] + len(cmol.atoms) + new_bo_dict[(ind1,ind2)]=mol.bo_dict[(bo[0],bo[1])] + + # connect metal to ligand + metal_ind = cmol.findMetal()[0] + for atom in catoms: + ind1 = metal_ind + ind2 = atom + len(cmol.atoms) + new_bo_dict[(ind1,ind2)]=1 + + for atom in mol.atoms: + cmol.addAtom(atom, auto_populate_BO_dict = False) + + cmol.bo_dict = new_bo_dict + return cmol + + def graph_from_bodict(self, bo_dict): + g = [] + for i, atom in enumerate(self.atoms): + sub_g = [] + connected = [] + for tup in bo_dict: + if i in tup: + if i != tup[0]: + connected.append(tup[0]) + else: + connected.append(tup[1]) + for j in range(0,len(self.atoms)): + if j in connected: + sub_g.append(1.) + else: + sub_g.append(0.) + g.append(sub_g) + return g From 73312b75a24f4ea2e9fb1f898e2c4d9ee58906c2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 00:22:50 +0000 Subject: [PATCH 07/19] [pre-commit.ci] auto fixes from pre-commit hooks --- molSimplify/Classes/mol3D.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/molSimplify/Classes/mol3D.py b/molSimplify/Classes/mol3D.py index bc26571f..cee6b9ce 100644 --- a/molSimplify/Classes/mol3D.py +++ b/molSimplify/Classes/mol3D.py @@ -6493,7 +6493,7 @@ def mol3D_to_networkx(self,get_symbols:bool=True,get_bond_order:bool=True,get_bo data['bond_distance']=distance g.add_edge(bond[0],bond[1],**data) return g - + def roland_combine(self, mol, catoms, bond_to_add=[], dirty=False): """ Combines two molecules. Each atom in the second molecule @@ -6527,7 +6527,7 @@ def roland_combine(self, mol, catoms, bond_to_add=[], dirty=False): new_bo_dict = copy.deepcopy(bo_dict) # add ligand connections - for bo in mol.bo_dict: + for bo in mol.bo_dict: ind1 = bo[0] + len(cmol.atoms) ind2 = bo[1] + len(cmol.atoms) new_bo_dict[(ind1,ind2)]=mol.bo_dict[(bo[0],bo[1])] From 1845b3a944942c05c179c2049c8405ee46363824 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:01:01 -0500 Subject: [PATCH 08/19] Update mol3D.py added import copy --- molSimplify/Classes/mol3D.py | 1 + 1 file changed, 1 insertion(+) diff --git a/molSimplify/Classes/mol3D.py b/molSimplify/Classes/mol3D.py index 31a57534..ea105983 100644 --- a/molSimplify/Classes/mol3D.py +++ b/molSimplify/Classes/mol3D.py @@ -10,6 +10,7 @@ import sys import tempfile import time +import copy import xml.etree.ElementTree as ET import numpy as np import networkx as nx From 15564168f5e46238fd44e1d10a7c48474fae61f1 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:06:38 -0500 Subject: [PATCH 09/19] Update structgen.py made dist a float --- molSimplify/Scripts/structgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/molSimplify/Scripts/structgen.py b/molSimplify/Scripts/structgen.py index 79c49036..de6ac248 100644 --- a/molSimplify/Scripts/structgen.py +++ b/molSimplify/Scripts/structgen.py @@ -3126,7 +3126,7 @@ def structgen(args: Namespace, rootdir: str, ligands: List[str], ligoc: List[int for bond in mol.bo_dict: atom0 = mol.atoms[bond[0]] atom1 = mol.atoms[bond[1]] - dist = -100000000000 + dist = -100000000000.0 if atom0.sym == 'C' and atom1.sym == 'H': dist = atom0.distance(atom1) L1 = np.array(tuple(atom0.coords())) From 66d7dd5276bd0ee24365a7927ec9e0e82aadeb5e Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:16:06 -0500 Subject: [PATCH 10/19] Update structgen.py caveats for more unforseen instances of core3D building --- molSimplify/Scripts/structgen.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/molSimplify/Scripts/structgen.py b/molSimplify/Scripts/structgen.py index de6ac248..44208929 100644 --- a/molSimplify/Scripts/structgen.py +++ b/molSimplify/Scripts/structgen.py @@ -2322,6 +2322,7 @@ def mcomplex(args: Namespace, ligs: List[str], ligoc: List[int] batslist: List[List[int]] = [] bats: List[int] = [] ffoption_list = [] # for each ligand, keeps track of what the forcefield option is. + copied = False # for determinining if core3D needs to be copied or not # load bond data MLbonds = loaddata('/Data/ML.dat') # calculate occurrences, denticities etc for all ligands @@ -2732,9 +2733,14 @@ def mcomplex(args: Namespace, ligs: List[str], ligoc: List[int] # combine molecules - if len(core3D.atoms) == 1: + if len(core3D.atoms) == 1 and copied == False: core3D_copy = mol3D() core3D_copy.copymol3D(core3D) + copied = True + elif copied == False: + core3D_copy = mol3D() + core3D_copy.copymol3D(core3D) + copied = True core3D_copy = core3D_copy.roland_combine(lig3D_copy, catoms) From 0fe26cd6a4e65722c5466252e40ed48ae5844b25 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:52:44 -0500 Subject: [PATCH 11/19] Update mol3D.py fixed writemol2 --- molSimplify/Classes/mol3D.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/molSimplify/Classes/mol3D.py b/molSimplify/Classes/mol3D.py index ea105983..ae6f8a78 100644 --- a/molSimplify/Classes/mol3D.py +++ b/molSimplify/Classes/mol3D.py @@ -3814,7 +3814,10 @@ def writemol2(self, filename, writestring=False, ignoreX=False, force=False): if atom.sym == 'X': self.deleteatom(i) if not len(self.graph): - self.createMolecularGraph() + if self.bo_dict: + self.graph = self.graph_from_bodict(self.bo_dict) + else: + self.createMolecularGraph() if not self.bo_dict and not force: self.convert2OBMol2() csg = csgraph.csgraph_from_dense(self.graph) @@ -3863,6 +3866,9 @@ def writemol2(self, filename, writestring=False, ignoreX=False, force=False): atom_types_mol2 = '' type_ind = atom_types.index(atom.sym) atom_coords = atom.coords() + if atom.sym == 'P': + pass + #print(atom_coords) ss += str(i+1) + ' ' + atom.sym+str(int(atom_type_numbers[type_ind])) + '\t' + \ '{} {} {} '.format(atom_coords[0], atom_coords[1], atom_coords[2]) + \ atom.sym + atom_types_mol2 + '\t' + atom_groups[i] + \ @@ -3875,14 +3881,20 @@ def writemol2(self, filename, writestring=False, ignoreX=False, force=False): bondorders = True else: bondorders = False + for i, b1 in enumerate(bonds[0]): - b2 = bonds[1][i] - if b2 > b1 and not bondorders: - ss += str(bond_count)+' '+str(b1+1) + ' ' + str(b2+1) + ' 1\n' - bond_count += 1 - elif b2 > b1 and bondorders: + if not bondorders: + b2 = bonds[1][i] + if b2 > b1: + ss += str(bond_count)+' '+str(b1+1) + ' ' + str(b2+1) + ' 1\n' + bond_count += 1 + if bondorders: + for bond in self.bo_dict: + b1 = bond[0] + b2 = bond[1] ss += str(bond_count)+' '+str(b1+1) + ' ' + str(b2+1) + \ ' {}\n'.format(self.bo_dict[(int(b1), int(b2))]) + bond_count += 1 ss += '@SUBSTRUCTURE\n' unique_group_names = np.unique(atom_group_names) for i, name in enumerate(unique_group_names): @@ -3898,7 +3910,7 @@ def writemol2(self, filename, writestring=False, ignoreX=False, force=False): filename = filename.split('.')[0]+'.mol2' with open(filename, 'w') as file1: file1.write(ss) - + def closest_H_2_metal(self, delta=0): """ Get closest hydrogen atom to metal. From cb913ccd4622d0d51b7b3c5b45ac08a4794fbdd4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:52:57 +0000 Subject: [PATCH 12/19] [pre-commit.ci] auto fixes from pre-commit hooks --- molSimplify/Classes/mol3D.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/molSimplify/Classes/mol3D.py b/molSimplify/Classes/mol3D.py index ae6f8a78..88fb6351 100644 --- a/molSimplify/Classes/mol3D.py +++ b/molSimplify/Classes/mol3D.py @@ -3910,7 +3910,7 @@ def writemol2(self, filename, writestring=False, ignoreX=False, force=False): filename = filename.split('.')[0]+'.mol2' with open(filename, 'w') as file1: file1.write(ss) - + def closest_H_2_metal(self, delta=0): """ Get closest hydrogen atom to metal. From 1f290549602e330d1436b0821a9cd900f9c31d17 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:42:11 -0500 Subject: [PATCH 13/19] Update structgen.py smart generation default change and addition to mcomplex --- molSimplify/Scripts/structgen.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/molSimplify/Scripts/structgen.py b/molSimplify/Scripts/structgen.py index 44208929..e5201fa2 100644 --- a/molSimplify/Scripts/structgen.py +++ b/molSimplify/Scripts/structgen.py @@ -2261,7 +2261,7 @@ def align_dent3_lig(args, cpoint, batoms, m3D, core3D, coreref, ligand, lig3D, return lig3D_aligned, frozenats, MLoptbds -def mcomplex(args: Namespace, ligs: List[str], ligoc: List[int] +def mcomplex(args: Namespace, ligs: List[str], ligoc: List[int], smart_generation: bool ) -> Tuple[mol3D, List[mol3D], str, run_diag, List[int], List[int]]: """Main ligand placement routine @@ -2821,7 +2821,8 @@ def mcomplex(args: Namespace, ligs: List[str], ligoc: List[int] core3D.writexyz('complex_after_final_ff.xyz') # core3D,enc = ffopt(args.ff,core3D,connected,1,frozenats,freezeangles,MLoptbds,'Adaptive',args.debug) - core3D.bo_dict = core3D_copy.bo_dict + if smart_generation == True: + core3D.bo_dict = core3D_copy.bo_dict return core3D, complex3D, emsg, this_diag, subcatoms_ext, mligcatoms_ext @@ -2955,7 +2956,7 @@ def generate_report(args: Namespace, ligands: List[str], ligoc: List[int] def structgen(args: Namespace, rootdir: str, ligands: List[str], ligoc: List[int], - sernum: int, write_files: bool = True, smart_generation: bool = True) -> Tuple[List[str], str, run_diag]: + sernum: int, write_files: bool = True, smart_generation: bool = False) -> Tuple[List[str], str, run_diag]: """Main structure generation routine - multiple structures Parameters @@ -2998,7 +2999,7 @@ def structgen(args: Namespace, rootdir: str, ligands: List[str], ligoc: List[int return strfiles, emsg, this_diag else: core3D, complex3D, emsg, this_diag, subcatoms_ext, mligcatoms_ext = mcomplex( - args, ligands, ligoc) + args, ligands, ligoc, smart_generation = smart_generation) if args.debug: print(('subcatoms_ext are ' + str(subcatoms_ext))) if emsg: From 5f645ebaa35612293c49e7883590db6eec5b2711 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:58:07 -0500 Subject: [PATCH 14/19] Update mol3D.py changed writemol2 to hopefully pass test --- molSimplify/Classes/mol3D.py | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/molSimplify/Classes/mol3D.py b/molSimplify/Classes/mol3D.py index 88fb6351..ea105983 100644 --- a/molSimplify/Classes/mol3D.py +++ b/molSimplify/Classes/mol3D.py @@ -3814,10 +3814,7 @@ def writemol2(self, filename, writestring=False, ignoreX=False, force=False): if atom.sym == 'X': self.deleteatom(i) if not len(self.graph): - if self.bo_dict: - self.graph = self.graph_from_bodict(self.bo_dict) - else: - self.createMolecularGraph() + self.createMolecularGraph() if not self.bo_dict and not force: self.convert2OBMol2() csg = csgraph.csgraph_from_dense(self.graph) @@ -3866,9 +3863,6 @@ def writemol2(self, filename, writestring=False, ignoreX=False, force=False): atom_types_mol2 = '' type_ind = atom_types.index(atom.sym) atom_coords = atom.coords() - if atom.sym == 'P': - pass - #print(atom_coords) ss += str(i+1) + ' ' + atom.sym+str(int(atom_type_numbers[type_ind])) + '\t' + \ '{} {} {} '.format(atom_coords[0], atom_coords[1], atom_coords[2]) + \ atom.sym + atom_types_mol2 + '\t' + atom_groups[i] + \ @@ -3881,20 +3875,14 @@ def writemol2(self, filename, writestring=False, ignoreX=False, force=False): bondorders = True else: bondorders = False - for i, b1 in enumerate(bonds[0]): - if not bondorders: - b2 = bonds[1][i] - if b2 > b1: - ss += str(bond_count)+' '+str(b1+1) + ' ' + str(b2+1) + ' 1\n' - bond_count += 1 - if bondorders: - for bond in self.bo_dict: - b1 = bond[0] - b2 = bond[1] + b2 = bonds[1][i] + if b2 > b1 and not bondorders: + ss += str(bond_count)+' '+str(b1+1) + ' ' + str(b2+1) + ' 1\n' + bond_count += 1 + elif b2 > b1 and bondorders: ss += str(bond_count)+' '+str(b1+1) + ' ' + str(b2+1) + \ ' {}\n'.format(self.bo_dict[(int(b1), int(b2))]) - bond_count += 1 ss += '@SUBSTRUCTURE\n' unique_group_names = np.unique(atom_group_names) for i, name in enumerate(unique_group_names): From 27b4f0ad0dc618831f077e6d7c547de256140f34 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:41:17 -0500 Subject: [PATCH 15/19] Update generator.py --- molSimplify/Scripts/generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/molSimplify/Scripts/generator.py b/molSimplify/Scripts/generator.py index 6429892f..d9290f01 100644 --- a/molSimplify/Scripts/generator.py +++ b/molSimplify/Scripts/generator.py @@ -236,7 +236,7 @@ def startgen(argv, flag, gui, inputfile_str=None, write_files=True): print(('adding ' + str(args.ligadd) + ' to ligand database with name ' + args.ligname + ' and connection atom(s) ' + str(args.ligcon))) addtoldb(smimol=args.ligadd, sminame=args.ligname, smident=len(args.ligcon), - smicat=str(args.ligcon).strip('[]'), smigrps="custom", smictg="custom", ffopt=args.ligffopt) + smicat=str(args.ligcon).strip('[]'), smigrps="custom", smictg="custom", ffopt=args.ligffopt, overwrite=args.overwrite) # normal structure generation or transition state building else: From 25676d1197d4e653dc3c6dc255492f56deb5aad4 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:43:30 -0500 Subject: [PATCH 16/19] Update inparse.py --- molSimplify/Scripts/inparse.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/molSimplify/Scripts/inparse.py b/molSimplify/Scripts/inparse.py index 6a58fc14..d16579c9 100644 --- a/molSimplify/Scripts/inparse.py +++ b/molSimplify/Scripts/inparse.py @@ -529,6 +529,7 @@ def parseinputfile(args, inputfile_str=None): args.dbvlinks = False args.rprompt = False set_rundir = False + args.overwrite = False # (we should remove these where posible) # THIS NEEDS CLEANING UP TO MINIMIZE DUPLICATION WITH parsecommandline @@ -582,8 +583,6 @@ def parseinputfile(args, inputfile_str=None): args.jobdir = l[1] else: args.jobdirblank = True - if (l[0] == '-no_tabs'): - args.no_tabs = True ### parse structure generation arguments ### if (l[0] == '-bind' and len(l[1:]) > 0): l = [_f for _f in re.split(' |,|\t', line) if _f] # noqa: E741 @@ -930,6 +929,8 @@ def parseinputfile(args, inputfile_str=None): args.ligcon = list_to_add[0] if (l[0] == '-ligffopt'): args.ffopt = l[1] + if (l[0] == '-overwrite'): + args.overwrite = l[1] # parse postprocessing arguments if (l[0] == '-postp'): args.postp = True @@ -1171,7 +1172,7 @@ def parseinputs_advanced(*p): "-calccharge", help="Automatically calculate net complex charge. By default this is ON.", default=True) parser.add_argument( "-genall", help="Generate complex both with and without FF opt, default False", action="store_true") # geometry - parser.add_argument("-decoration_index", help="list of indices on each ligand to decorate", + parser.add_argument("-decoration_index", help="list of indicies on each ligand to decorate", action="store_true") # decoration indexes, one list per ligand parser.add_argument("-decoration", help="list of SMILES for each decoratation", action="store_true") # decoration, one list ligand @@ -1196,8 +1197,6 @@ def parseinputs_advanced(*p): "-reportonly", help='add this flag if you just want the report, without actual structure generation. Currently does not support pentadentates.') parser.add_argument( "-jobmanager", help='use jobmanager naming convention.', default=False) - parser.add_argument( - "-no_tabs", help="add this flag to use spaces instead of tabs in written xyz files", default=False) if len(p) == 1: # only one input, printing help only args = parser.parse_args() return args From e5157142b77c80623e9a0ae0a880af6f525a6e42 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:57:15 -0500 Subject: [PATCH 17/19] Update inparse.py no_tabs fix 1 --- molSimplify/Scripts/inparse.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/molSimplify/Scripts/inparse.py b/molSimplify/Scripts/inparse.py index d16579c9..a1be70f7 100644 --- a/molSimplify/Scripts/inparse.py +++ b/molSimplify/Scripts/inparse.py @@ -583,6 +583,8 @@ def parseinputfile(args, inputfile_str=None): args.jobdir = l[1] else: args.jobdirblank = True + if (l[0] == '-no_tabs'): + args.no_tabs = True ### parse structure generation arguments ### if (l[0] == '-bind' and len(l[1:]) > 0): l = [_f for _f in re.split(' |,|\t', line) if _f] # noqa: E741 From 819343a76db4ea3d787955956cc839981ed4a8f3 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:58:08 -0500 Subject: [PATCH 18/19] Update inparse.py no_tabs fix 2 --- molSimplify/Scripts/inparse.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/molSimplify/Scripts/inparse.py b/molSimplify/Scripts/inparse.py index a1be70f7..5895fbea 100644 --- a/molSimplify/Scripts/inparse.py +++ b/molSimplify/Scripts/inparse.py @@ -1174,7 +1174,7 @@ def parseinputs_advanced(*p): "-calccharge", help="Automatically calculate net complex charge. By default this is ON.", default=True) parser.add_argument( "-genall", help="Generate complex both with and without FF opt, default False", action="store_true") # geometry - parser.add_argument("-decoration_index", help="list of indicies on each ligand to decorate", + parser.add_argument("-decoration_index", help="list of indices on each ligand to decorate", action="store_true") # decoration indexes, one list per ligand parser.add_argument("-decoration", help="list of SMILES for each decoratation", action="store_true") # decoration, one list ligand @@ -1199,6 +1199,8 @@ def parseinputs_advanced(*p): "-reportonly", help='add this flag if you just want the report, without actual structure generation. Currently does not support pentadentates.') parser.add_argument( "-jobmanager", help='use jobmanager naming convention.', default=False) + parser.add_argument( + "-no_tabs", help="add this flag to use spaces instead of tabs in written xyz files", default=False) if len(p) == 1: # only one input, printing help only args = parser.parse_args() return args From 7a86b9040e88e2248b5ab146f46dcd9feebb92e9 Mon Sep 17 00:00:00 2001 From: ReallyRoland <123595711+rolan701@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:26:07 -0500 Subject: [PATCH 19/19] Update test_inparse.py --- tests/test_inparse.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_inparse.py b/tests/test_inparse.py index 686ee2bd..2e6eb348 100644 --- a/tests/test_inparse.py +++ b/tests/test_inparse.py @@ -10,7 +10,8 @@ def test_parseinputfile_empty(): defaults = {'skipANN': False, 'oldANN': False, 'dbvdent': False, 'dbvconns': False, 'dbvhyb': False, 'dbvlinks': False, - 'rprompt': False, 'rundir': f'{os.getcwd()}/Runs'} + 'rprompt': False, 'rundir': f'{os.getcwd()}/Runs', + 'overwrite': False,} args = Namespace() parseinputfile(args, inputfile_str=' ')