|
#$Id: autodockNavigator.py 282 2016-12-05 01:15:03Z sarkiss $
"Virtual Screenening Controller"
from vsModel import VSModel
from dirNavigator import DirNavigator
import os, wx, StringIO, sys
from time import strftime
import wx.lib.scrolledpanel as scrolled
from MolKit.protein import Protein, Chain, Residue
class MolTreeSplitMacro(wx.SplitterWindow):
def __init__(self, parent):
wx.SplitterWindow.__init__(self, parent, -1,style = wx.SP_LIVE_UPDATE)
self.ligandTree = DirNavigator(self)
self.macromoleculeTree = DirNavigator(self)
self.SplitHorizontally(self.ligandTree, self.macromoleculeTree)
if wx.Platform == '__WXGTK__':#on mac bottom panel takes the whole space
self.SetSashGravity(0.5)
def AppendLigand(self, name, select=True):
"Adds a ligand to the tree"
fileName = name+'.pdbqt'
fullPath = os.path.join(self.ligandTree.basePath, fileName)
if self.ligandTree.treeDict.has_key(fullPath):
item = self.ligandTree.treeDict[fullPath]
else:
root = self.ligandTree.tree.RootItem
item = self.ligandTree.tree.AppendItem(root, fileName)
self.ligandTree.tree.SetItemImage(item, self.ligandTree.molIconIndex, wx.TreeItemIcon_Normal)
self.ligandTree.tree.SetPyData(item, fullPath)
self.ligandTree.treeDict[fullPath] = item
#self.ligandTree.tree.UnselectAll()
if select == True:
self.ligandTree.tree.SelectItem(item)
class AutoDockNavigator:
def __init__(self, frame):
self.vsModel = VSModel()
self.autodockTree = MolTreeSplitMacro(frame.navigator)
self.autodockTree.ligandTree.BuildTree(self.vsModel.ligandsFolder)
self.autodockTree.macromoleculeTree.BuildTree(self.vsModel.macromoleculesFolder)
self.autodockTree.macromoleculeTree.tree.UnselectAll()
from icons import adtPNG
frame.navigator.AddPage(self.autodockTree, 'AutoDock', bitmap=adtPNG)
self.frame = frame
frame.vsModel = self.vsModel
# self.autodockTree.Bind(wx.EVT_SHOW, self.SetActive)
#
# def SetActive(self, event):
# "This method is bound to wx.EVT_SHOW, i.e., invoked when this page is shown"
# try:
# self.autodockTree.ligandTree.OnRefresh(None)
# except: #might be called on exit; just to be on a safe side.
# pass
def AddLigand(self, mol, charges_to_add='gasteiger', select=True, use_=False):
"Creates ligand pdbqt, updates Ligands tree under Navigator > AutoDock and Ligands table under View > Tables"
mol.name = mol.name.replace(' ', '_')
mol.name = mol.name.replace('\t', '_')
mol_molDict = self.frame.TryCommand(self.vsModel.PrepareLigandMol, mol, charges_to_add=charges_to_add, use_=use_)
if mol_molDict:
mol, molDict = mol_molDict[0], mol_molDict[1]
else:
return None
self.autodockTree.AppendLigand(mol.name, select=select)
#database part
autodock_elements = ""
for item in molDict['autodock_element']:
autodock_elements += str(item) +" "
args = (mol.name, len(mol.allAtoms), strftime("%Y.%m.%d %H:%M:%S"), molDict['TORSDOF'], autodock_elements)
if not hasattr(self.frame.dbView, 'ligandsTable'):
self.frame.dbView.Activate(None)
self.frame.dbView.ligandsTable.AddItem(args)
return mol
def AddMacromolecule(self, mol):
"Creates pdbqt for macromolecule and updates Macromolecules tree under Navigator > AutoDock."
mol = self.CleanHetatms(mol)
if not mol: return
mol = self.SelectAlternate(mol)
if not mol: return
RPO = self.frame.TryCommand(self.vsModel.PrepareReceptorMol, mol)
self.RefreshMacroolecules()
item = self.autodockTree.macromoleculeTree.treeDict[self.vsModel.receptorFolder]
self.autodockTree.macromoleculeTree.tree.SelectItem(item)
if RPO:
return self.vsModel.macromoleculePath
else:
return None
def MakeFlexResidues(self, flexRes):
mol = self.SelectAlternate(flexRes[0].top)
if not mol: return
dlg = wx.ProgressDialog("Please Wait...", "Creating Flexible Residues...",
parent=self.frame, style = wx.PD_APP_MODAL)
if mol != flexRes[0].top:
fRes = []
for res in flexRes:
name = res.full_name()
fRes = mol.NodesFromName(name)
flexRes = fRes
self.frame.TryCommand(mol.buildBondsByDistance)
self.frame.TryCommand(self.vsModel.PrepareFlexReceptor, flexRes)
dlg.Destroy()
self.RefreshMacroolecules()
def RefreshMacroolecules(self):
self.autodockTree.macromoleculeTree.OnRefresh(None)
#self.autodockTree.macromoleculeTree.tree.UnselectAll()
#TODO: Replace wx.SplitterWindow with aui.notbook splited vertically
def CleanHetatms(self, mol):
"""Allow users to choose what to do with HETATMs"""
hetRes = []
hetatms = [atom for atom in mol.chains.residues.hetatm ]
for item in hetatms:
parent = item.parent
if len(parent.children) > 1: #for waters and other single atom residues in pdb
if len(parent.parent.children) > 3: continue #when hetatms are part of a bigger chain, keep it
if not parent in hetRes:
if parent.type in ["WAT", "HOH"]: continue
hetRes.append(parent)
if hetRes:
#ask user to select what to do with HETATMS
dlg = SelectHetDialog(self.frame, hetRes)
self.dlg = dlg #used for testing
if dlg.ShowModal() != wx.ID_OK:
dlg.Destroy()
return
for index, item in enumerate(dlg.boxes):
fate = item.GetCurrentSelection()
if fate == 1: #"Remove"
hetRes[index].parent.remove(hetRes[index])
for atom in hetRes[index].atoms:
hetRes[index].top.allAtoms.remove(atom)
#mol.chains.residues.remove(hetRes[index]) was not working
elif fate == 2: #"Remove and Save As pdbqt":
parser = hetRes[index].top.parser #hold on to parser otherwise, after adopt below it's gone. This is needed in AddLigand later.
hetRes[index].parent.residues.remove(hetRes[index])
for atom in hetRes[index].atoms:
hetRes[index].top.allAtoms.remove(atom)
ligand = Protein()
ligand.name = hetRes[index].name
chain= Chain()
chain.adopt(hetRes[index])
ligand.adopt(chain)
ligand.allAtoms = hetRes[index].atoms
ligand.allAtoms.top = ligand
ligand.parser = parser
self.AddLigand(ligand, select=False)
dlg.Destroy()
return mol
def SelectAlternate(self, mol):
"""Checks to see if there are alternate positions present in mol.
If there are atoms with alternate positions, then show SelectAltDialog which
allows users to select alternate conformation to retain.
"""
mol.name = mol.name.replace(' ', '_')
mol.name = mol.name.replace('\t', '_')
#check for alt conformations
altCounter = []
altDict = {}
altDictIndexes = {}
counter = 0
for index, item in enumerate(mol.allAtoms.altname):#handles alternates
if item:
name = mol.allAtoms[index].parent.name
if mol.allAtoms[index].parent.type in ["WAT", "HOH"]: continue
if altDict.has_key(name):
altDict[name].append(item)
altDictIndexes[name].append(index)
else:
altDict[name] = [item]
altDictIndexes[name] = [index]
altCounter.append(name)
if altCounter:
#ask user to select conformation
dlg = SelectAltDialog(self.frame, altDict, altCounter)
self.dlg = dlg #used for testing
if dlg.ShowModal() != wx.ID_OK:
dlg.Destroy()
return
remove_atoms = []
for index, item in enumerate(dlg.boxes):
name = altCounter[index]
altName = item.GetValue()
for atomIndex in altDictIndexes[name]:
if mol.allAtoms[atomIndex].altname != altName:
atom = mol.allAtoms[atomIndex]
for bond in atom.bonds:
if bond.atom1 != atom:
del bond.atom1.bonds[bond.atom1.bonds.index(bond)]
else:
del bond.atom2.bonds[bond.atom2.bonds.index(bond)]
parent = atom.parent
i = parent.atoms.index(atom)
parent.atoms.__delitem__(i)
remove_atoms.append(atom)
else:
atom = mol.allAtoms[atomIndex]
atom.altname = None
atom.name = atom.name.replace("@"+altName,"")
for atom in remove_atoms:
mol.allAtoms.remove(atom)
dlg.Destroy()
return mol
class SelectHetDialog(wx.Dialog):
"Select Dialog for HETATM"
def __init__(self, parent, hetRes):
pre = wx.PreDialog()
pre.Create(parent, -1, "Make Macromolecule - HETATM")
# This next step is the most important, it turns this Python
# object into the real wrapper of the dialog (instead of pre)
# as far as the wxPython extension is concerned.
self.PostCreate(pre)
# This extra style can be set after the UI object has been created.
if 'wxMac' in wx.PlatformInfo:
self.SetExtraStyle(wx.DIALOG_EX_METAL)
self.boxes = [] #this list stores Combo Boxes
# Now continue with the normal construction of the dialog
# contents
sPanel = scrolled.ScrolledPanel(self)
mainSizer = wx.BoxSizer(wx.VERTICAL)
sizer = wx.BoxSizer(wx.VERTICAL)
label = wx.StaticText(sPanel, -1, """ How to handle non-standard residues (HETATM) :
- Keep (include in the final pdbqt).
- Remove (remove before making pdbqt).
- Remove and Save As (ligand) pdbqt.
Press Enter to accept these defaults.""")
sizer.Add(label, 0, wx.ALIGN_LEFT|wx.ALL, 5)
fate = "Keep"
if len(hetRes) < 5:
fate = "Remove and Save As pdbqt"
for res in hetRes:
box = wx.BoxSizer(wx.HORIZONTAL)
#add residue here
label = wx.StaticText(sPanel, -1, res.full_name())
box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 10)
cb = wx.Choice(sPanel, -1,
choices = ["Keep", "Remove", "Remove and Save As pdbqt"],
)
if len(res.atoms) < 4: # for HOH
fate = "Remove"
cb.SetStringSelection(fate)
self.boxes.append(cb)
box.Add(cb, 1, wx.ALIGN_CENTRE|wx.ALL, 2)
sizer.Add(box, 0, wx.GROW|wx.ALIGN_LEFT|wx.RIGHT|wx.LEFT, 5)
sPanel.SetSizer( sizer )
line = wx.StaticLine(sPanel, -1, size=(20,-1), style=wx.LI_HORIZONTAL)
sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5)
btnsizer = wx.StdDialogButtonSizer()
btn = wx.Button(sPanel, wx.ID_OK)
btn.SetDefault()
btnsizer.AddButton(btn)
btn = wx.Button(sPanel, wx.ID_CANCEL)
btnsizer.AddButton(btn)
btnsizer.Realize()
sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
mainSizer.Add(sPanel, 2, wx.EXPAND)
self.SetSizer(mainSizer)
sizer.Fit(self)
if len(hetRes) > 10:
sPanel.SetAutoLayout(1)
sPanel.SetupScrolling(scroll_x=False)
class SelectAltDialog(wx.Dialog):
"Select Conformation Dialog"
def __init__(self, parent, altDict, altCounter):
pre = wx.PreDialog()
pre.Create(parent, -1, "Select Conformation")
# This next step is the most important, it turns this Python
# object into the real wrapper of the dialog (instead of pre)
# as far as the wxPython extension is concerned.
self.PostCreate(pre)
# This extra style can be set after the UI object has been created.
if 'wxMac' in wx.PlatformInfo:
self.SetExtraStyle(wx.DIALOG_EX_METAL)
self.boxes = [] #this list stores Combo Boxes
# Now continue with the normal construction of the dialog
# contents
sPanel = scrolled.ScrolledPanel(self)
mainSizer = wx.BoxSizer(wx.VERTICAL)
sizer = wx.BoxSizer(wx.VERTICAL)
label = wx.StaticText(sPanel, -1, """ Select alternate conformations.
Press Enter to accept these defaults.""")
sizer.Add(label, 0, wx.ALIGN_LEFT|wx.ALL, 5)
for name in altCounter:
box = wx.BoxSizer(wx.HORIZONTAL)
#add residue here
label = wx.StaticText(sPanel, -1, name)
box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 2)
cb = wx.ComboBox(sPanel, 500, altDict[name][0], (90, 50),
(160, -1), list( set(altDict[name]) ),
wx.CB_DROPDOWN | wx.CB_READONLY | wx.CB_SORT )
self.boxes.append(cb)
box.Add(cb, 1, wx.ALIGN_CENTRE|wx.ALL, 2)
sizer.Add(box, 0, wx.GROW|wx.ALIGN_LEFT|wx.RIGHT|wx.LEFT, 5)
sPanel.SetSizer( sizer )
line = wx.StaticLine(sPanel, -1, size=(20,-1), style=wx.LI_HORIZONTAL)
sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5)
btnsizer = wx.StdDialogButtonSizer()
btn = wx.Button(sPanel, wx.ID_OK)
btn.SetDefault()
btnsizer.AddButton(btn)
btn = wx.Button(sPanel, wx.ID_CANCEL)
btnsizer.AddButton(btn)
btnsizer.Realize()
sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
mainSizer.Add(sPanel, 2, wx.EXPAND)
self.SetSizer(mainSizer)
sizer.Fit(self)
if len(altCounter) > 10:
sPanel.SetAutoLayout(1)
sPanel.SetupScrolling(scroll_x=False)
|