diff --git a/InteractiveROSETTA/InteractiveROSETTA.py b/InteractiveROSETTA/InteractiveROSETTA.py old mode 100644 new mode 100755 index 97534a4..3dad7a0 --- a/InteractiveROSETTA/InteractiveROSETTA.py +++ b/InteractiveROSETTA/InteractiveROSETTA.py @@ -468,7 +468,7 @@ def importModules(wxpython=False): if ("### LICENSE ACCEPTED ###" in aline): license_accepted = license_accepted + 1 f.close() - if (license_accepted < 3): + if (license_accepted < 3 and platform.system() != "Windows"): # Windows users accept the license through the installer # Make sure we are root on OSX/Linux # On Windows, the batch script that starts InteractiveROSETTA makes sure they are the Admin if (platform.system() != "Windows" and os.getuid() != 0 and not(os.access("InteractiveROSETTA.py", os.W_OK))): diff --git a/InteractiveROSETTA/linux_install.sh b/InteractiveROSETTA/linux_install.sh index ba3a0e3..c37e8ba 100644 --- a/InteractiveROSETTA/linux_install.sh +++ b/InteractiveROSETTA/linux_install.sh @@ -1,5 +1,13 @@ #!/bin/bash +if [ -t 1 ]; then + echo "Installing InteractiveROSETTA" + echo "" +else + notify-send "Please run this installer in a terminal" + exit +fi + if [ $EUID == 0 ]; then echo "Do not run this script as root. You will be prompted for the root password when necessary." exit @@ -138,6 +146,12 @@ cd /usr/local/InteractiveROSETTA # Get the molfile stuff sudo python molfile.py + +# Update the PyMOL splash screen +SPLASHDIR=`python -c "import pymol; print pymol.__file__[0:pymol.__file__.rfind(\"/\")] + \"/pymol_path/data/pymol\""` +sudo mv $SPLASHDIR/splash.png $SPLASHDIR/original_splash.png +sudo cp images/pymol_splash.png $SPLASHDIR/splash.png + cd "$REALOLDDIR" # Create a desktop shortcut diff --git a/InteractiveROSETTA/scripts/advresiduecreator.py b/InteractiveROSETTA/scripts/advresiduecreator.py index a8c5d8c..3dace31 100644 --- a/InteractiveROSETTA/scripts/advresiduecreator.py +++ b/InteractiveROSETTA/scripts/advresiduecreator.py @@ -15,7 +15,6 @@ dlg = wx.MessageDialog(None, "ERROR: molfile_to_params not found\nDid you forget to unpack it?\n\nOSX/Linux: Perform \"sudo molfile.py\"", "Molfile_to_params Missing", wx.OK | wx.ICON_ERROR | wx.CENTRE) dlg.ShowModal() dlg.Destroy() - import molfile_to_params import webbrowser from tools import * diff --git a/InteractiveROSETTA/scripts/compmodel.py b/InteractiveROSETTA/scripts/compmodel.py index 540b368..413df32 100644 --- a/InteractiveROSETTA/scripts/compmodel.py +++ b/InteractiveROSETTA/scripts/compmodel.py @@ -11,6 +11,7 @@ import webbrowser from threading import Thread from tools import * +from Bio.Align.Applications import MuscleCommandline class CompModelPanel(wx.lib.scrolledpanel.ScrolledPanel): def __init__(self, parent, W, H): @@ -55,32 +56,69 @@ def __init__(self, parent, W, H): self.lblInst.SetForegroundColour("#FFFFFF") if (platform.system() == "Windows"): - self.lblModel = wx.StaticText(self, -1, "Templates", (0, 190), (155, 20), wx.ALIGN_CENTRE) + self.lblFASTA = wx.StaticText(self, -1, "FASTA Sequence:", (10, 90), (320, 20), wx.ALIGN_LEFT) + self.lblFASTA.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + elif (platform.system() == "Darwin"): + self.lblFASTA = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblFASTA.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(10, 90), size=(320, 20)) + else: + self.lblFASTA = wx.StaticText(self, -1, "FASTA Sequence:", (10, 90), style=wx.ALIGN_LEFT) + self.lblFASTA.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + self.lblFASTA.SetForegroundColour("#FFFFFF") + self.txtFASTA = wx.TextCtrl(self, -1, pos=(0, 110), size=(320, 75), style=wx.TE_MULTILINE) + self.txtFASTA.SetValue("") + self.txtFASTA.SetToolTipString("FASTA sequence of the protein that will be modeled") + self.txtFASTA.Bind(wx.EVT_KILL_FOCUS, self.fastaChange) + self.FASTA = "" + + if (platform.system() == "Windows"): + self.lblProt2 = wx.StaticText(self, -1, "Homologous Templates", (0, 190), (320, 25), wx.ALIGN_CENTRE) + self.lblProt2.SetFont(wx.Font(12, wx.DEFAULT, wx.ITALIC, wx.BOLD)) + elif (platform.system() == "Darwin"): + self.lblProt2 = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblHomologyTemplates.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(25, 190), size=(270, 25)) + else: + self.lblProt2 = wx.StaticText(self, -1, "Homologous Templates", (70, 190), style=wx.ALIGN_CENTRE) + self.lblProt2.SetFont(wx.Font(12, wx.DEFAULT, wx.ITALIC, wx.BOLD)) + resizeTextControlForUNIX(self.lblProt2, 0, self.GetSize()[0]-20) + self.lblProt2.SetForegroundColour("#FFFFFF") + + if (platform.system() == "Windows"): + self.lblInst2 = wx.StaticText(self, -1, "Provide scaffolds that the above sequence will\nbe threaded onto. Templates higher in the grid\nare given more priority. Click on templates in\nthe grid to edit their alignments.", (0, 220), (320, 25), wx.ALIGN_CENTRE) + self.lblInst2.SetFont(wx.Font(10, wx.DEFAULT, wx.ITALIC, wx.NORMAL)) + elif (platform.system() == "Darwin"): + self.lblInst2 = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblInstHomologyTemplates.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(0, 220), size=(320, 95)) + else: + self.lblInst2 = wx.StaticText(self, -1, "Provide scaffolds that the above sequence will\nbe threaded onto. Templates higher in the grid\nare given more priority. Click on templates in\nthe grid to edit their alignments.", (5, 220), style=wx.ALIGN_CENTRE) + self.lblInst2.SetFont(wx.Font(10, wx.DEFAULT, wx.ITALIC, wx.NORMAL)) + resizeTextControlForUNIX(self.lblInst2, 0, self.GetSize()[0]-20) + self.lblInst2.SetForegroundColour("#FFFFFF") + + if (platform.system() == "Windows"): + self.lblModel = wx.StaticText(self, -1, "Templates", (0, 290), (155, 20), wx.ALIGN_CENTRE) self.lblModel.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) elif (platform.system() == "Darwin"): - self.lblModel = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblModelCompModel.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(0, 190), size=(155, 20)) + self.lblModel = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblModelCompModel.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(0, 290), size=(155, 20)) else: - self.lblModel = wx.StaticText(self, -1, "Templates", (0, 190), style=wx.ALIGN_CENTRE) + self.lblModel = wx.StaticText(self, -1, "Templates", (0, 290), style=wx.ALIGN_CENTRE) self.lblModel.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) resizeTextControlForUNIX(self.lblModel, 0, 155) self.lblModel.SetForegroundColour("#FFFFFF") - self.modelMenu = wx.ComboBox(self, pos=(0, 210), size=(155, 25), choices=[], style=wx.CB_READONLY) - self.modelMenu.Bind(wx.EVT_COMBOBOX, self.modelMenuSelect) + self.modelMenu = wx.ComboBox(self, pos=(0, 310), size=(155, 25), choices=[], style=wx.CB_READONLY) self.modelMenu.SetToolTipString("Select the models to serve as templates for structure prediction") self.templates = [] + self.alignments = [] if (platform.system() == "Darwin"): - self.btnAddTemplate = wx.BitmapButton(self, id=-1, bitmap=wx.Image(self.parent.parent.scriptdir + "/images/osx/btnAddFragments.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(165, 210), size=(77, 25)) + self.btnAddTemplate = wx.BitmapButton(self, id=-1, bitmap=wx.Image(self.parent.parent.scriptdir + "/images/osx/btnAddFragments.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(165, 310), size=(77, 25)) else: - self.btnAddTemplate = wx.Button(self, id=-1, label="Add", pos=(165, 210), size=(77, 25)) + self.btnAddTemplate = wx.Button(self, id=-1, label="Add", pos=(165, 310), size=(77, 25)) self.btnAddTemplate.SetForegroundColour("#000000") self.btnAddTemplate.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) self.btnAddTemplate.Bind(wx.EVT_BUTTON, self.addModel) self.btnAddTemplate.SetToolTipString("Add model to the list of templates") if (platform.system() == "Darwin"): - self.btnRemoveTemplate = wx.BitmapButton(self, id=-1, bitmap=wx.Image(self.parent.parent.scriptdir + "/images/osx/btnRemoveFragments.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(242, 210), size=(78, 25)) + self.btnRemoveTemplate = wx.BitmapButton(self, id=-1, bitmap=wx.Image(self.parent.parent.scriptdir + "/images/osx/btnRemoveFragments.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(242, 310), size=(78, 25)) else: - self.btnRemoveTemplate = wx.Button(self, id=-1, label="Remove", pos=(242, 210), size=(78, 25)) + self.btnRemoveTemplate = wx.Button(self, id=-1, label="Remove", pos=(242, 310), size=(78, 25)) self.btnRemoveTemplate.SetForegroundColour("#000000") self.btnRemoveTemplate.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) self.btnRemoveTemplate.Bind(wx.EVT_BUTTON, self.removeModel) @@ -89,56 +127,74 @@ def __init__(self, parent, W, H): self.grdTemplates = wx.grid.Grid(self) self.grdTemplates.CreateGrid(0, 1) self.grdTemplates.SetSize((320, 150)) - self.grdTemplates.SetPosition((0, 240)) + self.grdTemplates.SetPosition((0, 340)) self.grdTemplates.SetLabelFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) self.grdTemplates.DisableDragColSize() self.grdTemplates.DisableDragRowSize() self.grdTemplates.SetColLabelValue(0, "Templates") self.grdTemplates.SetRowLabelSize(160) self.grdTemplates.SetColSize(0, 160) + self.grdTemplates.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.gridClick) + self.selectedr = -1 + ypos = self.grdTemplates.GetPosition()[1] + self.grdTemplates.GetSize()[1] + 10 - self.lblFrag = wx.StaticText(self, -1, "None Uploaded", pos=(10, 403), size=(180, 25), style=wx.ALIGN_CENTRE) - self.lblFrag.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) - if (platform.system() == "Linux"): - resizeTextControlForUNIX(self.lblFrag, 10, 180) - self.lblFrag.SetForegroundColour("#FFFFFF") + self.btnMoveUp = wx.BitmapButton(self, id=-1, bitmap=wx.Image(self.parent.parent.scriptdir + "/images/up-arrow.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(0, ypos), size=(25, 25)) + self.btnMoveUp.Bind(wx.EVT_BUTTON, self.moveUp) + self.btnMoveUp.SetToolTipString("Add model to the list of templates") + self.btnMoveDown = wx.BitmapButton(self, id=-1, bitmap=wx.Image(self.parent.parent.scriptdir + "/images/down-arrow.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(295, ypos), size=(25, 25)) + self.btnMoveDown.Bind(wx.EVT_BUTTON, self.moveDown) + self.btnMoveDown.SetToolTipString("Remove model from the list of templates") if (platform.system() == "Darwin"): - self.btnLoad = wx.BitmapButton(self, id=-1, bitmap=wx.Image(self.parent.parent.scriptdir + "/images/osx/btnLoadFrag.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(200, 400), size=(110, 25)) + self.btnLoadAlign = wx.BitmapButton(self, id=-1, bitmap=wx.Image(self.parent.parent.scriptdir + "/images/osx/btnLoadAlign.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(30, ypos), size=(127, 25)) else: - self.btnLoad = wx.Button(self, id=-1, label="Load Frag", pos=(200, 400), size=(110, 25)) - self.btnLoad.SetForegroundColour("#000000") - self.btnLoad.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) - self.btnLoad.Bind(wx.EVT_BUTTON, self.loadFrag) - self.btnLoad.SetToolTipString("Load a frag GZ file") - self.loadedfile = "" - + self.btnLoadAlign = wx.Button(self, id=-1, label="Load Alignment", pos=(30, ypos), size=(127, 25)) + self.btnLoadAlign.SetForegroundColour("#000000") + self.btnLoadAlign.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + self.btnLoadAlign.Bind(wx.EVT_BUTTON, self.loadAlign) + self.btnLoadAlign.SetToolTipString("Load a previously-saved alignment for this template-target pair") if (platform.system() == "Darwin"): - self.scoretypeMenu = wx.ComboBox(self, pos=(7, 430), size=(305, 25), choices=[], style=wx.CB_READONLY) + self.btnSaveAlign = wx.BitmapButton(self, id=-1, bitmap=wx.Image(self.parent.parent.scriptdir + "/images/osx/btnSaveAlign.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(163, ypos), size=(127, 25)) + else: + self.btnSaveAlign = wx.Button(self, id=-1, label="Save Alignment", pos=(163, ypos), size=(127, 25)) + self.btnSaveAlign.SetForegroundColour("#000000") + self.btnSaveAlign.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + self.btnSaveAlign.Bind(wx.EVT_BUTTON, self.saveAlign) + self.btnSaveAlign.SetToolTipString("Load a previously-saved alignment for this template-target pair") + + if (platform.system() == "Windows"): + self.lblAlignment = wx.StaticText(self, -1, "Alignment:", (10, ypos+30), (320, 20), wx.ALIGN_LEFT) + self.lblAlignment.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + elif (platform.system() == "Darwin"): + self.lblAlignment = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblAlignment.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(10, ypos+30), size=(320, 20)) else: - self.scoretypeMenu = wx.ComboBox(self, pos=(7, 430), size=(305, 25), choices=[], style=wx.CB_READONLY | wx.CB_SORT) - self.scoretypeMenu.Bind(wx.EVT_COMBOBOX, self.scoretypeMenuSelect) - self.scoretypeMenu.Disable() # Is only enabled after a design and before accepting it - self.scoretypeMenu.SetToolTipString("Scoretype by which PyMOL residues will be colored") + self.lblAlignment = wx.StaticText(self, -1, "Alignment:", (10, ypos+30), style=wx.ALIGN_LEFT) + self.lblAlignment.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + self.lblAlignment.SetForegroundColour("#FFFFFF") + self.txtAlignment = wx.TextCtrl(self, -1, pos=(0, ypos+50), size=(320, 125), style=wx.TE_MULTILINE | wx.TE_READONLY) + self.txtAlignment.SetValue("") + self.txtAlignment.SetFont(wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.NORMAL, wx.NORMAL)) + self.txtAlignment.SetToolTipString("Alignment of the currently selected model") + self.txtAlignment.Bind(wx.EVT_KEY_DOWN, self.alignmentEdit) + self.maxsize = 30 if (platform.system() == "Windows"): - self.lblModelView = wx.StaticText(self, -1, "View Structure:", (20, 463), (120, 20), wx.ALIGN_CENTRE) - self.lblModelView.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + self.lblNumModels = wx.StaticText(self, -1, "Models to Generate:", (0, ypos+193), (260, 20), wx.ALIGN_CENTRE) + self.lblNumModels.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) elif (platform.system() == "Darwin"): - self.lblModelView = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblModelView.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(20, 463), size=(120, 20)) + self.lblNumModels = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblNumModels.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(0, ypos+193), size=(260, 20)) else: - self.lblModelView = wx.StaticText(self, -1, "View Structure:", (20, 463), style=wx.ALIGN_CENTRE) - self.lblModelView.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) - resizeTextControlForUNIX(self.lblModelView, 20, 120) - self.lblModelView.SetForegroundColour("#FFFFFF") - self.viewMenu = wx.ComboBox(self, pos=(175, 460), size=(120, 25), choices=[], style=wx.CB_READONLY) - self.viewMenu.Bind(wx.EVT_COMBOBOX, self.viewMenuSelect) - self.viewMenu.Disable() - self.viewMenu.SetToolTipString("Select model positions to view in PyMOL") + self.lblNumModels = wx.StaticText(self, -1, "Models to Generate:", (0, ypos+193), style=wx.ALIGN_CENTRE) + self.lblNumModels.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + resizeTextControlForUNIX(self.lblNumModels, 0, 260) + self.lblNumModels.SetForegroundColour("#FFFFFF") + self.txtNumModels = wx.TextCtrl(self, -1, pos=(260, ypos+190), size=(60, 25)) + self.txtNumModels.SetValue("10") + self.txtNumModels.SetToolTipString("Number of comparative models to generate (1-100)") if (platform.system() == "Darwin"): - self.btnThread = wx.BitmapButton(self, id=-1, bitmap=wx.Image(self.parent.parent.scriptdir + "/images/osx/btnThread.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(110, 490), size=(100, 25)) + self.btnThread = wx.BitmapButton(self, id=-1, bitmap=wx.Image(self.parent.parent.scriptdir + "/images/osx/btnThread.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(110, ypos+220), size=(100, 25)) else: - self.btnThread = wx.Button(self, id=-1, label="Thread!", pos=(110, 490), size=(100, 25)) + self.btnThread = wx.Button(self, id=-1, label="Thread!", pos=(110, ypos+220), size=(100, 25)) self.btnThread.SetForegroundColour("#000000") self.btnThread.SetFont(wx.Font(10, wx.DEFAULT, wx.ITALIC, wx.BOLD)) self.btnThread.Bind(wx.EVT_BUTTON, self.threadClick) @@ -176,119 +232,88 @@ def setSelectWin(self, selectWin): def activate(self): if (self.seqWin): - # Find out which models are selected and the locations of their poses - selection = self.seqWin.getSelectedResidues() - rowsSelected = [] - for line in selection: - rowsSelected.append(line[0]) - if (len(rowsSelected) == 0): - # If nothing selected, select all models - if (self.seqWin.numChains() > 0): - rowsSelected = range(0, self.seqWin.numChains()) - else: - return + # Select all models + if (self.seqWin.numChains() > 0): + rowsSelected = range(0, self.seqWin.numChains()) + else: + return self.models = [] for r in rowsSelected: ID = self.seqWin.IDs[r] - model = self.seqWin.getModelForChain(r) - if (not(model in self.models)): - self.models.append(str(model)) - # Update the combo box to have these models as selections - self.modelMenu.Clear() - self.modelMenu.AppendItems(self.models) - if (len(self.models) > 0): - if (platform.system() == "Windows"): - # Doing this on Linux freezes up the ComboBox, so don't do it on Linux - self.modelMenu.SetSelection(0) - - def uploadFASTA(self, event): - if (len(self.txtFASTA.GetValue().strip()) > 0): - dlg = wx.MessageDialog(self, "Your current FASTA sequence will be replaced with the loaded data. Do you want to continue?", "Replace FASTA Data", wx.YES_NO | wx.ICON_EXCLAMATION | wx.CENTRE) - if (dlg.ShowModal() == wx.ID_YES): - # Don't clear it out until the user actually selects a resfile (instead of cancelling - # at the file selection dialog - pass - else: - logInfo("Upload FASTA operation canceled due to data already being present in the text box.") - return - dlg = wx.FileDialog( - self, message="Choose a File", - defaultDir=self.seqWin.cwd, - defaultFile="", - wildcard="All Files (*)|*", - style=wx.OPEN | wx.CHANGE_DIR) - if (dlg.ShowModal() == wx.ID_OK): - paths = dlg.GetPaths() - # Change cwd to the last opened file - lastDirIndx = paths[len(paths)-1].rfind("/") - self.seqWin.cwd = str(paths[len(paths)-1][0:lastDirIndx]) - self.seqWin.saveWindowData(None) - filename = str(paths[0]) - # Does it open? If yes, then erase the resfile data and continue - try: - f = open(filename, "r") - except: - wx.MessageBox("The file " + filename.strip() + " cannot be opened!", "File Cannot Be Read", wx.OK|wx.ICON_EXCLAMATION) - return - logInfo("Loaded data from a FASTA file", filename) - fastastr = "" - for aline in f: - fastastr = fastastr + aline.strip() + "\n" - self.txtFASTA.SetValue(fastastr) - f.close() - - def fragGen(self, event): - webbrowser.open("http://robetta.bakerlab.org/fragmentsubmit.jsp") - dlg = wx.MessageDialog(self, "After submitting a job, please make note of the job ID integer and specify it below so InteractiveROSETTA can watch for it to be completed.", "Specify Job ID", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - dlg.ShowModal() - dlg.Destroy() + self.models.append(str(ID)) + if (self.models != self.modelMenu.GetItems()): + # Update the combo box to have these models as selections + self.modelMenu.Clear() + self.modelMenu.AppendItems(self.models) + if (len(self.models) > 0): + if (platform.system() == "Windows"): + # Doing this on Linux freezes up the ComboBox, so don't do it on Linux + self.modelMenu.SetSelection(0) + # Take out templates that are not loaded + self.txtAlignment.SetValue("") + self.selectedr = -1 + for i in range(len(self.templates)-1, -1, -1): + if (self.templates[i] not in self.models): + self.templates.pop(i) + self.alignments.pop(i) + self.updateGrid() - def jobWatch(self, event): - # First ask if the ID is valid (it has to be an integer, no letters) - if (len(self.txtJobID.GetValue().strip()) == 0): - dlg = wx.MessageDialog(self, "Please specify a job ID!", "Job ID Required", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - dlg.ShowModal() - dlg.Destroy() - return - try: - int(self.txtJobID.GetValue()) - except: - dlg = wx.MessageDialog(self, "Please specify a valid job ID! Valid Job IDs are integers.", "Job ID Invalid", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - dlg.ShowModal() - dlg.Destroy() - return - # Now write this to a text file - # A timer on the SequenceWindow will use this information to look for the files to appear on the Robetta server - goToSandbox() - # First make sure this isn't a duplicate - alreadythere = False - try: - f = open("downloadwatch", "r") - for aline in f: - if (len(aline.split("\t")) >= 2 and aline.split("\t")[0] == "FRAGMENT" and aline.split("\t")[1] == str(txtJobID.GetValue().strip())): - alreadythere = True - break - f.close() - except: - pass - if (not(alreadythere)): - f = open("downloadwatch", "a") - f.write("FRAGMENT\t" + str(self.txtJobID.GetValue()) + "\t" + str(datetime.datetime.now()) + "\n") - f.close() - dlg = wx.MessageDialog(self, "InteractiveROSETTA is now watching the Robetta server for job ID " + str(self.txtJobID.GetValue()) + ". You will be notified when the package is available for download.", "Listening for Download", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - dlg.ShowModal() - dlg.Destroy() + def recolorModel(self, modelchain): + # Recolor the model such that aligned portions of the model are shown in purple + # and unaligned structure is in cyan + # Purple: Aligned regions, will grab from template in comparative modeling + # Cyan: Deletions, will not be present at all in the final model + # Yellow: Insertion, will attempt to add a loop in this region + addToSelection = False + model = modelchain[0:len(modelchain)-2] + chain = modelchain[len(modelchain)-1] + r = self.seqWin.IDs.index(modelchain) + c = 1 + # Save the locations of where the insertions will occur + insertions = [] + for i in range(0, len(self.alignments[self.selectedr][0])): + if (self.alignments[self.selectedr][0][i] != "-" and self.alignments[self.selectedr][1][i] != "-"): + self.seqWin.selectNthResidue(r, c, addToSelection, updateSelection=False) + addToSelection = True + if (self.alignments[self.selectedr][0][i] != "-" and self.alignments[self.selectedr][1][i] == "-" and c not in insertions): + insertions.append(c-1) + if (self.alignments[self.selectedr][1][i] != "-"): + c += 1 + self.seqWin.selectUpdate(True) + self.cmd.set("ribbon_color", "purple", "seqsele") + self.cmd.set("cartoon_color", "purple", "seqsele") + if (chain != "_"): + self.cmd.set("ribbon_color", "cyan", "model " + model + " and chain " + chain + " and not seqsele") + self.cmd.set("cartoon_color", "cyan", "model " + model + " and chain " + chain + " and not seqsele") + else: + self.cmd.set("ribbon_color", "cyan", "model " + model + " and not seqsele") + self.cmd.set("cartoon_color", "cyan", "model " + model + " and not seqsele") + addToSelection = False + for c in insertions: + self.seqWin.selectNthResidue(r, c, addToSelection, updateSelection=False) + addToSelection = True + self.seqWin.selectUpdate(True) + self.cmd.set("ribbon_color", "yellow", "seqsele") + self.cmd.set("cartoon_color", "yellow", "seqsele") + self.cmd.disable("seqsele") + self.cmd.delete("seqsele") - def showModel(self, model): + def showModel(self, modelchain): + model = modelchain[0:len(modelchain)-2] + chain = modelchain[len(modelchain)-1] defaultPyMOLView(self.cmd) - self.cmd.select("sele", "model " + model) + if (chain != "_"): + self.cmd.select("sele", "model " + model + " and chain " + chain) + else: + self.cmd.select("sele", "model " + model) self.cmd.zoom("sele") self.cmd.hide("everything", "not sele") - self.seqWin.selectUpdate(False) + self.recolorModel(modelchain) + #self.seqWin.selectUpdate(False) def modelMenuSelect(self, event): logInfo("Selected model " + self.modelMenu.GetValue()) - self.showModel(self.modelMenu.GetStringSelection()) + #self.showModel(self.modelMenu.GetStringSelection()) def updateGrid(self): if (self.grdTemplates.NumberRows > 0): @@ -302,12 +327,382 @@ def updateGrid(self): self.grdTemplates.SetRowLabelValue(i, "") self.grdTemplates.SetCellValue(i, 0, self.templates[i]) + def drawAlignment(self, indx): + # Renders the alignment in txtAlignment in formal output + # Columns 1-4: Targ/1st 4 letters of scaffold + # Column 5: Blank + # Columns 6+: Alignment + self.alignmentstr = "" + # First look to see if we have any gaps aligned to other gaps and remove them + for i in range(len(self.alignments[indx][0])-1, -1, -1): + if (self.alignments[indx][0][i] == "-" and self.alignments[indx][1][i] == "-"): + self.alignments[indx][0] = self.alignments[indx][0][0:i] + self.alignments[indx][0][i+1:] + self.alignments[indx][1] = self.alignments[indx][1][0:i] + self.alignments[indx][1][i+1:] + for i in range(0, len(self.alignments[indx][0]), self.maxsize): + self.alignmentstr += "Targ " + self.alignments[indx][0][i:i+self.maxsize] + "\n" + self.alignmentstr += self.templates[indx][0:4] + " " + self.alignments[indx][1][i:i+self.maxsize] + "\n\n" + self.txtAlignment.SetValue(self.alignmentstr) + + def alignmentEdit(self, event): + (selpos, end) = self.txtAlignment.GetSelection() + if (selpos != end): + return + # Now we have to do some math and make sure the insertion is in the actual alignment + # and not in header information or the blank line + if (platform.system() == "Windows"): + # Apparently in Windows text boxes newlines register as 2 characters instead of 1 -_- + linewidth = 16 + 2*self.maxsize # Two alignments, each line has 5 header columns, and 3 newlines + targstart = 5 + tempstart = 12+self.maxsize + offset = 1 + else: + linewidth = 13 + 2*self.maxsize # Two alignments, each line has 5 header columns, and 3 newlines + targstart = 5 + tempstart = 11+self.maxsize + offset = 0 + linepos = selpos + block = 0 + while (linepos >= linewidth): + linepos -= linewidth + block += 1 + # Only the SPACEBAR, BACKSPACE, and DELETE keys change the sequence + # Arrow keys are supported to move the cursor around + if (int(event.GetKeyCode()) == wx.WXK_SPACE): + if (linepos < 5 or (linepos > 5+self.maxsize and linepos < 11+self.maxsize) or linepos > 11+2*self.maxsize): + return + # Put a gap in this location and add a gap to the end of the other sequence + shift = True + if (linepos <= targstart+self.maxsize): + # Selection in target sequence + p = linepos - targstart + block * self.maxsize + seq = 0 + else: + p = linepos - tempstart + block * self.maxsize + seq = 1 + self.alignments[self.selectedr][seq] = self.alignments[self.selectedr][seq][0:p] + "-" + self.alignments[self.selectedr][seq][p:] + if (self.alignments[self.selectedr][seq].endswith("-")): + self.alignments[self.selectedr][seq] = self.alignments[self.selectedr][seq][0:len(self.alignments[self.selectedr][seq])-1] + else: + self.alignments[self.selectedr][1-seq] += "-" + if (self.alignments[self.selectedr][1-seq][p] == "-"): + # The doubly-aligned - will be eliminated by drawAlignment + shift = False + # Redrawing the alignment resets the scrollbars, this gets the original scroll position back + vpos = self.txtAlignment.GetScrollPos(wx.VERTICAL) + self.drawAlignment(self.selectedr) + self.txtAlignment.SetScrollPos(wx.VERTICAL, vpos) + if (shift): + # Move the cursor + if (linepos == targstart+self.maxsize or linepos == targstart+self.maxsize): + # We're at the edge of a line and need to shift by a whole block + linepos -= self.maxsize + block += 1 + linepos += 1 + selpos = linepos + block * linewidth + self.txtAlignment.SetSelection(selpos, selpos) + # Alignment changed, update coloring + self.recolorModel(self.templates[self.selectedr]) + elif (int(event.GetKeyCode()) == wx.WXK_BACK or int(event.GetKeyCode()) == wx.WXK_DELETE or (platform.system() == "Darwin" and int(event.GetKeyCode()) == 8)): + # Backspace deletes the gap before the current position and delete deletes the current gap + if (int(event.GetKeyCode()) == wx.WXK_BACK or (platform.system() == "Darwin" and int(event.GetKeyCode()) == wx.WXK_DELETE)): + if (linepos < targstart or (linepos > targstart+self.maxsize and linepos < tempstart) or linepos > tempstart+self.maxsize): + return + # Put a gap in this location and add a gap to the end of the other sequence + shift = True + if (linepos <= targstart+self.maxsize): + # Selection in target sequence + p = linepos - targstart + block * self.maxsize + seq = 0 + else: + p = linepos - tempstart + block * self.maxsize + seq = 1 + if (p-1 < 0 or self.alignments[self.selectedr][seq][p-1] != "-"): + # You can only delete gaps + return + self.alignments[self.selectedr][seq] = self.alignments[self.selectedr][seq][0:p-1] + self.alignments[self.selectedr][seq][p:] + "-" + else: + if (linepos < targstart or (linepos > targstart+self.maxsize and linepos < tempstart) or linepos > tempstart+self.maxsize): + return + # Put a gap in this location and add a gap to the end of the other sequence + shift = False + if (linepos <= targstart+self.maxsize): + # Selection in target sequence + p = linepos - targstart + block * self.maxsize + seq = 0 + else: + p = linepos - tempstart + block * self.maxsize + seq = 1 + if (p >= len(self.alignments[self.selectedr][seq]) or self.alignments[self.selectedr][seq][p] != "-"): + # You can only delete gaps + return + self.alignments[self.selectedr][seq] = self.alignments[self.selectedr][seq][0:p] + self.alignments[self.selectedr][seq][p+1:] + "-" + # Redrawing the alignment resets the scrollbars, this gets the original scroll position back + vpos = self.txtAlignment.GetScrollPos(wx.VERTICAL) + self.drawAlignment(self.selectedr) + self.txtAlignment.SetScrollPos(wx.VERTICAL, vpos) + if (shift): + # Move the cursor + if (linepos == targstart or linepos == tempstart): + # We're at the edge of a line and need to shift by a whole block + linepos += self.maxsize + block -= 1 + linepos -= 1 + selpos = linepos + block * linewidth + self.txtAlignment.SetSelection(selpos, selpos) + # Alignment changed, update coloring + self.recolorModel(self.templates[self.selectedr]) + elif (int(event.GetKeyCode()) == wx.WXK_LEFT): + if (linepos <= targstart and block == 0): + linepos = targstart + elif (linepos <= tempstart and linepos > targstart+self.maxsize and block == 0): + linepos = tempstart + elif (linepos < targstart): + linepos = targstart + elif (linepos < tempstart and linepos > targstart+self.maxsize): + linepos = tempstart + elif (linepos > tempstart+self.maxsize): + linepos = tempstart+self.maxsize + elif (linepos == targstart or linepos == tempstart): + linepos += self.maxsize + block -= 1 + else: + linepos -= 1 + selpos = linepos + block * linewidth + self.txtAlignment.SetSelection(selpos, selpos) + elif (int(event.GetKeyCode()) == wx.WXK_RIGHT): + if (linepos < targstart): + linepos = targstart + elif (linepos < tempstart and linepos > targstart+self.maxsize): + linepos = tempstart + elif (linepos > tempstart+self.maxsize): + linepos = targstart + block += 1 + elif (linepos == targstart+self.maxsize or linepos == tempstart+self.maxsize): + # We're at the edge of a line and need to shift by a whole block + linepos -= self.maxsize + block += 1 + else: + linepos += 1 + # Okay, the last line is weird since it doesn't have to be self.maxsize in length + # Did we go past the end of a sequence? + if (linepos <= targstart+self.maxsize): + # Selection in target sequence + p = linepos - targstart + block * self.maxsize + seq = 0 + else: + p = linepos - tempstart + block * self.maxsize + seq = 1 + if (p >= len(self.alignments[self.selectedr][seq])): + p = len(self.alignments[self.selectedr][seq]) + if (seq == 0): + linepos = p - (block * self.maxsize) + targstart + else: + linepos = p - (block * self.maxsize) + tempstart + selpos = linepos + block * linewidth + if (selpos >= len(self.alignmentstr)): + # Block is pushing it passed the end of the string + selpos = linepos + (block-1) * linewidth + self.txtAlignment.SetSelection(selpos, selpos) + elif (int(event.GetKeyCode()) == wx.WXK_UP): + # Again, that last line is annoying since it doesn't have to be maxsize in length + lastblock = int(len(self.alignments[self.selectedr][0]) / self.maxsize) + if (block == lastblock): + maxsize = len(self.alignments[self.selectedr][0]) - lastblock * self.maxsize + if (linepos < targstart+maxsize): + # Still on the top row, so maxsize should not be changed since we're going + # up into the previous block which has a full alignment row + maxsize = self.maxsize + else: + tempstart = tempstart - self.maxsize + maxsize + else: + maxsize = self.maxsize + # Move up to the next higher sequence if possible + if (linepos <= targstart and block == 0): + # In the header region on the first line + linepos = targstart + elif (linepos <= tempstart and linepos > targstart+maxsize and block == 0): + # In the header region on the first alignment, lower sequence + linepos = targstart + elif (linepos <= targstart): + # In header region of target sequence + linepos = tempstart + offset + block -= 1 + elif (linepos < tempstart and linepos > targstart+maxsize): + # In header region of the scaffold sequence + linepos = targstart + #block -= 1 + elif (linepos > tempstart+maxsize): + # In the gap between alignment blocks + linepos = 11+maxsize + offset + elif (linepos <= targstart+maxsize and block > 0): + # In target sequence, move up to scaffold sequence in previous block + linepos += targstart + maxsize + 1 + offset + block -= 1 + elif (linepos >= tempstart and linepos <= tempstart+maxsize): + # In scaffold sequence, move up to the target in the same block + linepos -= targstart + maxsize + 1 + offset + selpos = linepos + block * linewidth + self.txtAlignment.SetSelection(selpos, selpos) + elif (int(event.GetKeyCode()) == wx.WXK_DOWN): + # Again, that last line is annoying since it doesn't have to be maxsize in length + lastblock = int(len(self.alignments[self.selectedr][0]) / self.maxsize) + lastmaxsize = len(self.alignments[self.selectedr][0]) - lastblock * self.maxsize + # Move down to the next lower sequence if possible + if (linepos <= targstart and block == 0): + # In the header region on the first line + linepos = tempstart + elif (linepos <= targstart): + # In header region of target sequence + linepos = tempstart + elif (linepos < tempstart and linepos > targstart+self.maxsize): + # In header region of the scaffold sequence + linepos = targstart + block += 1 + elif (linepos > tempstart+self.maxsize and block != lastblock): + # In the gap between alignment blocks, not in the last alignment block + linepos = targstart + block += 1 + elif (linepos <= targstart+self.maxsize and block < lastblock): + # In target sequence, move down to scaffold sequence in same block + linepos += targstart + self.maxsize + 1 + offset + elif (linepos <= targstart+self.maxsize and block == lastblock): + # In target sequence in the last block, shift by the length of the last block + linepos += targstart + lastmaxsize + 1 + offset + elif (linepos >= tempstart and linepos <= tempstart+self.maxsize and block < lastblock-1): + # In scaffold sequence, move down to the target in the next block + linepos -= targstart + self.maxsize + 1 + offset + block += 1 + elif (linepos >= tempstart and linepos <= tempstart+self.maxsize and block == lastblock-1): + # In scaffold sequence but moving to last block, check to make sure we don't go past the edge of the alignment + linepos -= targstart + self.maxsize + 1 + offset + block += 1 + if (linepos > targstart+lastmaxsize): + linepos = targstart+lastmaxsize + else: + # In scaffold of last block, move the cursor to the end of the scaffold + linepos = tempstart+lastmaxsize + selpos = linepos + block * linewidth + self.txtAlignment.SetSelection(selpos, selpos) + # Select this residue (or the one before if in a gap) in the sequence window + (selpos, end) = self.txtAlignment.GetSelection() + linepos = selpos + block = 0 + while (linepos >= linewidth): + linepos -= linewidth + block += 1 + if (linepos <= targstart+self.maxsize): + # Selection in target sequence + p = linepos - targstart + block * self.maxsize + else: + p = linepos - tempstart + block * self.maxsize + # Find the row + for i in range(0, len(self.seqWin.IDs)): + if (self.templates[self.selectedr] == self.seqWin.IDs[i]): + r = i + break + # Find the residue + c = 0 + for i in range(0, p+1): + if (c >= len(self.alignments[self.selectedr][1])): + break + if (self.alignments[self.selectedr][1][i] != "-"): + c += 1 + self.seqWin.selectNthResidue(r, c) + + def regenerateAlignments(self, indx=-1): + # Uses MUSCLE to recalculate the alignments when a change occurs + # If MUSCLE is not available, a default alignment will be given and the user will + # have to align manually + if (indx < 0): + indx = 0 + l = len(self.alignments) + else: + l = indx + 1 + goToSandbox() + if (platform.system() == "Windows"): + muscle = self.parent.parent.scriptdir + "\\bin\\muscle_win.exe" + else: + muscle = self.parent.parent.scriptdir + "/bin/muscle_unix" + for i in range(indx, l): + # Generate the MUSCLE input + fout = open("muscle.in", "w") + fout.write("> Target\n") + fout.write(self.FASTA.strip() + "\n\n") + fout.write("> Scaffold\n") + # Get the sequence + modelchain = self.templates[i] + seq = "" + for r in range(0, len(self.seqWin.sequences)): + if (modelchain == self.seqWin.IDs[r]): + seq += self.seqWin.sequences[r] + fout.write(seq + "\n") + fout.close() + # Try to align with MUSCLE + try: + muscle_cline = MuscleCommandline(muscle, input="muscle.in", out="muscle.out") + muscle_cline() + # Read the results + targetseq = "" + scaffoldseq = "" + onScaffold = False + fin = open("muscle.out", "r") + for aline in fin: + if (aline.startswith("> Scaffold")): + onScaffold = True + elif (len(aline.strip()) == 0 or aline.strip()[0] == ">"): + continue + elif (onScaffold): + scaffoldseq += aline.strip() + else: + targetseq += aline.strip() + fin.close() + self.alignments.append([targetseq, scaffoldseq]) + except: + print "WARNING: MUSCLE could not be found at " + muscle + argetseq = self.FASTA + scaffoldseq = seq + if (len(targetseq) < len(scaffoldseq)): + for j in range(0, len(scaffoldseq)-len(targetseq)): + targetseq += "-" + else: + for j in range(0, len(targetseq)-len(scaffoldseq)): + scaffoldseq += "-" + self.alignments.append([targetseq, scaffoldseq]) + if (self.selectedr >= 0): + self.drawAlignment(self.selectedr) + + def fastaChange(self, event): + # Scan the current contents of this text box and take out everything that is invalid + data = self.txtFASTA.GetValue()#.strip() + fastaOnly = "" + for aline in data.split("\n"): + if (aline.strip().startswith(">")): + continue + fastaOnly += aline + fastaOnly = str(fastaOnly.replace(" ", "").replace("\t", "").upper()) + newseq = "" + for AA in fastaOnly: + if (AA not in "ACDEFGHIKLMNPQRSTVWY"): + dlg = wx.MessageDialog(self, "The amino acid " + AA + " is not valid. It will be ignored.", "Invalid Amino Acid", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + dlg.ShowModal() + dlg.Destroy() + else: + newseq += AA + if (newseq != self.FASTA): + self.regenerateAlignments() + self.FASTA = newseq + self.txtFASTA.SetValue(self.FASTA) + self.txtFASTA.SetSelection(len(self.FASTA), len(self.FASTA)) + event.Skip() + def addModel(self, event): # Add this to the list of template structures model = str(self.modelMenu.GetValue()) + if (model not in self.modelMenu.GetItems()): + return if (not(model in self.templates)): self.templates.append(model) - self.templates.sort() + self.regenerateAlignments(len(self.templates)-1) # Update the grid with this new information self.updateGrid() logInfo("Added " + model + " to the list of model structures") @@ -318,43 +713,56 @@ def removeModel(self, event): if (model in self.templates): indx = self.templates.index(model) self.templates.pop(indx) + self.alignments.pop(indx) # Update the grid with this new information self.updateGrid() logInfo("Removed " + model + " from the list of static chains") - def loadFrag(self, event): - # Get the structure from a MOL2 file and load it into PyMOL - logInfo("Load Frag button clicked") - dlg = wx.FileDialog( - self, message="Choose a File", - defaultDir=self.seqWin.cwd, - defaultFile="", - wildcard="Frag Files (*.frag)|*.frag", - style=wx.OPEN | wx.CHANGE_DIR) - if (dlg.ShowModal() == wx.ID_OK): - paths = dlg.GetPaths() - # Change cwd to the last opened file - if (platform.system() == "Windows"): - lastDirIndx = paths[len(paths)-1].rfind("\\") + def selectRow(self, row): + self.selectedr = row + if (self.selectedr >= self.grdTemplates.NumberRows): + self.selectedr = -1 + for r in range(0, self.grdTemplates.NumberRows): + if (r == self.selectedr): + for c in range(0, self.grdTemplates.NumberCols): + self.grdTemplates.SetCellBackgroundColour(r, c, "light blue") else: - lastDirIndx = paths[len(paths)-1].rfind("/") - self.seqWin.cwd = str(paths[len(paths)-1][0:lastDirIndx]) - self.seqWin.saveWindowData(None) - filename = str(paths[0]) - self.loadedfile = filename - localfilename = filename[lastDirIndx+1:] - self.lblFrag.SetLabel(localfilename) - self.lblFrag.SetForegroundColour("#FFFFFF") - else: - logInfo("Load PDB operation cancelled") + for c in range(0, self.grdTemplates.NumberCols): + self.grdTemplates.SetCellBackgroundColour(r, c, "white") + self.grdTemplates.Refresh() + self.showModel(self.templates[self.selectedr]) + + def gridClick(self, event): + self.selectRow(event.GetRow()) + if (len(self.FASTA.strip()) > 0): + self.drawAlignment(self.selectedr) + event.Skip() - def viewMenuSelect(self, event): - try: - self.focusView(self.viewMenu.GetStringSelection(), self.selectedModel, "thread_view") - logInfo("Viewing " + self.viewMenu.GetStringSelection()) - except: - # Probably the user left the field blank, do nothing - pass + def moveUp(self, event): + # Move the selected template up in the ranking + if (self.selectedr > 0): + temp = self.templates[self.selectedr] + self.templates[self.selectedr] = self.templates[self.selectedr-1] + self.templates[self.selectedr-1] = temp + temp = self.alignments[self.selectedr] + self.alignments[self.selectedr] = self.alignments[self.selectedr-1] + self.alignments[self.selectedr-1] = temp + self.updateGrid() + self.selectedr -= 1 + self.selectRow(self.selectedr) + + def moveDown(self, event): + # Move the selected template down in the ranking + if (self.selectedr >= 0 and self.selectedr < len(self.templates)-1): + temp = self.templates[self.selectedr] + self.templates[self.selectedr] = self.templates[self.selectedr+1] + self.templates[self.selectedr+1] = temp + temp = self.alignments[self.selectedr] + self.alignments[self.selectedr] = self.alignments[self.selectedr+1] + self.alignments[self.selectedr+1] = temp + self.updateGrid() + self.selectedr += 1 + self.selectRow(self.selectedr) def focusView(self, posID, origmodel, newmodel=None): if (posID != "Whole View"): @@ -394,260 +802,202 @@ def focusView(self, posID, origmodel, newmodel=None): self.cmd.delete("viewsele") self.cmd.delete("exviewsele") - def scoretypeMenuSelect(self, event): - # Make sure there is even a PyMOL_Mover pose loaded - if (self.selectedModel == ""): + def loadAlign(self, event): + logInfo("Load Alignment button clicked") + # Is a row selected? + if (len(self.txtAlignment.GetValue().strip()) == 0): + dlg = wx.MessageDialog(self, "Please select a template from the grid whose alignment is the one attempting to be loaded.", "No Template Selected", wx.OK | wx.ICON_ERROR | wx.CENTRE) + dlg.ShowModal() + dlg.Destroy() return - logInfo("Changed scoretype view to " + self.scoretypeMenu.GetStringSelection()) - recolorEnergies(self.threadView, self.residue_E, "thread_view", self.scoretypeMenu.GetStringSelection(), self.cmd) - self.viewMenuSelect(event) # To update all the labels + dlg = wx.FileDialog( + self, message="Choose a File", + defaultDir=self.seqWin.cwd, + defaultFile="", + wildcard="Alignments (*.fasta)|*.fasta", + style=wx.OPEN | wx.CHANGE_DIR) + if (dlg.ShowModal() == wx.ID_OK): + paths = dlg.GetPaths() + # Change cwd to the last opened file + if (platform.system() == "Windows"): + lastDirIndx = paths[len(paths)-1].rfind("\\") + else: + lastDirIndx = paths[len(paths)-1].rfind("/") + self.seqWin.cwd = str(paths[len(paths)-1][0:lastDirIndx]) + self.seqWin.saveWindowData(None) + filename = str(paths[0]) + # Does it open? If yes, then erase the resfile data and continue + try: + f = open(filename, "r") + except: + wx.MessageBox("The file " + filename.strip() + " cannot be opened!", "File Cannot Be Read", wx.OK|wx.ICON_EXCLAMATION) + return + logInfo("Loaded data from a FASTA alignment", filename) + # Read the sequences out of the alignment file + targseq = "" + readingtarg = False + readingtemp = False + tempseq = "" + fin = open(filename, "r") + for aline in fin: + if (aline.startswith("> Target")): + readingtarg = True + elif (readingtarg and aline.startswith(">")): + # Does the ID in here match the one selected? + ID = aline[2:].strip() + if (ID != self.templates[self.selectedr]): + dlg = wx.MessageDialog(self, "The PDB IDs in the alignment file do not match.\n\nSelected template: " + self.templates[self.selectedr] + "\nFound: " + ID, "PDB IDs Do Not Match", wx.OK | wx.ICON_ERROR | wx.CENTRE) + dlg.ShowModal() + dlg.Destroy() + return + readingtemp = True + readingtarg = False + elif (readingtemp and aline.startswith(">")): + break + elif (readingtarg): + targseq += aline.strip() + elif (readingtemp): + tempseq += aline.strip() + fin.close() + # Do the sequences match the sequences of the current FASTA and template? + currtarg = "" + currtemp = "" + loadtarg = "" + loadtemp = "" + for AA in self.alignments[self.selectedr][0]: + if (AA != "-"): + currtarg += AA + for AA in self.alignments[self.selectedr][1]: + if (AA != "-"): + currtemp += AA + for AA in targseq: + if (AA != "-"): + loadtarg += AA + for AA in tempseq: + if (AA != "-"): + loadtemp += AA + if (currtarg != loadtarg): + dlg = wx.MessageDialog(self, "The target sequence in the alignment file does not match the current sequence given above!", "Target Sequences Do Not Match", wx.OK | wx.ICON_ERROR | wx.CENTRE) + dlg.ShowModal() + dlg.Destroy() + print currtarg + print loadtarg + return + if (currtemp != loadtemp): + dlg = wx.MessageDialog(self, "The template sequence in the alignment file does not match the sequence of the selected template!", "Template Sequences Do Not Match", wx.OK | wx.ICON_ERROR | wx.CENTRE) + dlg.ShowModal() + dlg.Destroy() + print currtemp + print loadtemp + return + # If we made it this far, then the sequences should be good + self.alignments[self.selectedr][0] = targseq + self.alignments[self.selectedr][1] = tempseq + self.drawAlignment(self.selectedr) + self.recolorModel(self.templates[self.selectedr]) + + def saveAlign(self, event): + # Is an alignment even there? + if (len(self.txtAlignment.GetValue().strip()) == 0): + dlg = wx.MessageDialog(self, "There is no alignment to save!", "No Alignment", wx.OK | wx.ICON_ERROR | wx.CENTRE) + dlg.ShowModal() + dlg.Destroy() + return + # Okay, now just save the alignment in FASTA format for later use + dlg = wx.FileDialog( + self, message="Save an alignment", + defaultDir=self.seqWin.cwd, + defaultFile="", + wildcard="Alignments (*.fasta)|*.fasta", + style=wx.SAVE | wx.CHANGE_DIR) + if (dlg.ShowModal() == wx.ID_OK): + paths = dlg.GetPaths() + # Change cwd to the last opened file + if (platform.system() == "Windows"): + lastDirIndx = paths[len(paths)-1].rfind("\\") + else: + lastDirIndx = paths[len(paths)-1].rfind("/") + self.seqWin.cwd = str(paths[len(paths)-1][0:lastDirIndx]) + self.seqWin.saveWindowData(None) + filename = str(paths[0]).split(".fasta")[0] + ".fasta" + # Does it exist already? If so, ask if the user really wants to overwrite it + if (os.path.isfile(filename)): + dlg2 = wx.MessageDialog(self, "The file " + filename + " already exists. Overwrite it?", "Filename Already Exists", wx.YES_NO | wx.ICON_QUESTION | wx.CENTRE) + if (dlg2.ShowModal() == wx.ID_NO): + dlg2.Destroy() + logInfo("Canceled save operation due to filename already existing") + fout = open(filename, "w") + fout.write("> Target\n\n") + for i in range(0, len(self.alignments[self.selectedr][0]), 50): + fout.write(self.alignments[self.selectedr][0][i:i+50] + "\n") + fout.write("\n> " + self.templates[self.selectedr].strip() + "\n\n") + for i in range(0, len(self.alignments[self.selectedr][1]), 50): + fout.write(self.alignments[self.selectedr][1][i:i+50] + "\n") + fout.close() def threadClick(self, event): + logInfo("Clicked the Thread button") # This is also the "Finalize!" button if (self.buttonState == "Thread!"): - # Make sure there is at least one template structure specified and that a frag gz file is specified - if (len(self.templates) == 0): - wx.MessageBox("Please select at least one loaded model as a template for threading!", "Template Required", wx.OK|wx.ICON_EXCLAMATION) - return - if (len(self.loadedfile.strip()) == 0): - wx.MessageBox("Please indicate a FRAG file generated from the FASTA sequence that will be modeled. Use Robetta to generate this if you have not done so already.", "Movable Chain Required", wx.OK|wx.ICON_EXCLAMATION) - return - self.seqWin.labelMsg.SetLabel("Performing protein threading, please be patient...") - self.seqWin.labelMsg.SetFont(wx.Font(10, wx.DEFAULT, wx.ITALIC, wx.BOLD)) - self.seqWin.labelMsg.SetForegroundColour("#FFFFFF") - self.seqWin.msgQueue.append("Performing protein threading, please be patient...") - self.seqWin.cannotDelete = True - self.parent.GoBtn.Disable() - self.btnAddTemplate.Disable() - self.btnRemoveTemplate.Disable() - self.btnLoad.Disable() - self.btnThread.Disable() - self.stage = 1 - logInfo("Clicked the Thread button") - self.tmrThread = wx.Timer(self) - self.Bind(wx.EVT_TIMER, self.threadThread, self.tmrThread) - self.tmrThread.Start(1000) - else: - # Finalize button, ask whether the changes will be accepted or rejected - dlg = wx.MessageDialog(self, "Do you want to accept the threaded model?", "Accept/Reject Model", wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION | wx.CENTRE) - result = dlg.ShowModal() - if (result == wx.ID_YES): - logInfo("Accepted threaded model") - accept = True - elif (result == wx.ID_NO): - logInfo("Rejected threaded model") - accept = False - else: - logInfo("Canceled Finalize operation") - dlg.Destroy() + # Do we have a FASTA sequence? + if (len(self.FASTA.strip()) == 0): + wx.MessageBox("You need to input a FASTA sequence whose structure will be predicted!", "FASTA Sequence Required", wx.OK|wx.ICON_ERROR) return - dlg.Destroy() - self.viewMenu.Disable() - self.scoretypeMenu.Disable() - self.parent.GoBtn.Enable() - self.btnAddTemplate.Enable() - self.btnRemoveTemplate.Enable() - self.btnLoad.Enable() - if (platform.system() == "Darwin"): - self.btnThread.SetBitmapLabel(bitmap=wx.Image(self.parent.parent.scriptdir + "/images/osx/btnThread.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap()) - else: - self.btnThread.SetLabel("Finalize!") - self.buttonState = "Thread!" - self.btnThread.SetToolTipString("Perform docking simulation with selected parameters") - self.cmd.label("all", "") - self.seqWin.cannotDelete = False - if (not(accept)): - self.cmd.remove("thread_view") - self.cmd.delete("thread_view") + # Do we have at least one template? + if (len(self.templates) == 0): + wx.MessageBox("You need to provide at least one homologous structure that will be used for modeling!", "Homologous Structure Required", wx.OK|wx.ICON_ERROR) return - # Load the structure in PyMOL and the sequence viewer - if (platform.system() == "Windows"): - newname = os.path.expanduser("~") + "\\thread_T.pdb" - else: - newname = os.path.expanduser("~") + "/thread_T.pdb" - os.rename(self.selectedModel, newname) + # Do we have a valid number of models? try: - self.cmd.remove("thread_view") - self.cmd.delete("thread_view") - self.cmd.load(newname, "thread_T") - defaultPyMOLView(self.cmd, "thread_T") - self.seqWin.PyMOLPDBLoad(0, newname) - del self.threadView + nmodels = int(self.txtNumModels.GetValue()) + if (nmodels < 1 or nmodels > 100): + raise Exception() except: - # Some weird error happened, do nothing instead of crashing - print "Bug at accept button click" - pass - - def recoverFromError(self, msg=""): - # This function tells the user what the error was and tries to revert the protocol - # back to the pre-daemon state so the main GUI can continue to be used - if (len(msg) == 0): - f = open("errreport", "r") - errmsg = "An error was encountered during the protocol:\n\n" - for aline in f: - errmsg = errmsg + str(aline) - f.close() - os.remove("errreport") - else: - errmsg = msg - logInfo("Error Encountered") - logInfo(errmsg) - if (platform.system() == "Windows"): - sessioninfo = os.path.expanduser("~") + "\\InteractiveRosetta\\sessionlog" - else: - sessioninfo = os.path.expanduser("~") + "/InteractiveRosetta/sessionlog" - errmsg = errmsg + "\n\nIf you don't know what caused this, send the file " + sessioninfo + " to a developer along with an explanation of what you did." - # You have to use a MessageDialog because the MessageBox doesn't always work for some reason - dlg = wx.MessageDialog(self, errmsg, "Error Encountered", wx.OK|wx.ICON_EXCLAMATION) - dlg.ShowModal() - dlg.Destroy() - self.seqWin.cannotDelete = False - self.parent.GoBtn.Enable() - self.btnAddTemplate.Enable() - self.btnRemoveTemplate.Enable() - self.btnLoad.Enable() - self.btnThread.SetLabel("Thread!") - self.btnThread.SetToolTipString("Begin threading the sequence onto the template structures") - # Get rid of the messages - for i in range(0, len(self.seqWin.msgQueue)): - if (self.seqWin.msgQueue[i].find("Performing protein threading") >= 0): - self.seqWin.msgQueue.pop(i) - break - if (len(self.seqWin.msgQueue) > 0): - self.seqWin.labelMsg.SetLabel(self.seqWin.msgQueue[len(self.seqWin.msgQueue)-1]) - else: - self.seqWin.labelMsg.SetLabel("") - self.seqWin.labelMsg.SetFont(wx.Font(10, wx.DEFAULT, wx.ITALIC, wx.BOLD)) - self.seqWin.labelMsg.SetForegroundColour("#FFFFFF") - - def threadThread(self, event): - # Dump a file with the loop modeling parameters for the daemon to pick up - goToSandbox() - if (self.stage == 1): - self.tmrThread.Stop() - self.timeoutCount = 0 - f = open("threadinputtemp", "w") - for pdb in self.templates: - f.write("PDBFILE\t" + pdb.strip() + ".pdb\n") - f2 = open(pdb.strip() + ".pdb", "r") - f.write("BEGIN PDB DATA\n") - for aline in f2: - f.write(aline.strip() + "\n") - f.write("END PDB DATA\n") - f2.close() - f.write("FRAG\t" + self.loadedfile + "\n") - f.close() + wx.MessageBox("Please enter an integer from 1-100 for the number of models.", "Invalid Number of Models", wx.OK|wx.ICON_ERROR) + return + # Write the input file + fout = open("threadinputtemp", "w") + fout.write("FASTA\t" + self.FASTA.strip() + "\n") + fout.write("NMODELS\t" + str(nmodels) + "\n") + indx = 1 + for template in self.templates: + chain = template[len(template)-1] + fout.write("PDBFILE\tPRT" + str(indx) + chain + ".pdb\n") + indx += 1 + fout.write("BEGIN PDB DATA\n") + fin = open(template[0:len(template)-2] + ".pdb", "r") + for aline in fin: + if ((aline.startswith("ATOM") or aline.startswith("HETATM")) and aline[21] == template[len(template)-1]): + fout.write(aline) + fin.close() + fout.write("END PDB DATA\n") + for i in range(0, len(self.alignments)): + fout.write("TARGALIGN\t" + self.alignments[i][0].strip() + "\n") + fout.write("TEMPALIGN\t" + self.alignments[i][1].strip() + "\n") + fout.close() appendScorefxnParamsInfoToFile("threadinputtemp", self.selectWin.weightsfile) - if (useServer and False): - try: - self.ID = sendToServer("threadinput") - self.usingServer = True - logInfo("Threading input sent to server daemon with ID " + self.ID) + # Try to send it to the server + try: + self.ID = sendToServer("threadinput") + # First make sure this isn't a duplicate + alreadythere = False + try: + f = open("downloadwatch", "r") + for aline in f: + if (len(aline.split("\t")) >= 2 and aline.split("\t")[0] == "COMPMODEL" and aline.split("\t")[1] == self.ID.strip()): + alreadythere = True + break + f.close() except: - # Something failed, default to the local daemon - os.rename("threadinputtemp", "threadinput") - self.usingServer = False - logInfo("Server daemon not available, threading input uploaded at threadinput") - else: - os.rename("threadinputtemp", "threadinput") - self.usingServer = False - logInfo("Threading input uploaded locally at threadinput") - self.stage = 2 - self.tmrThread.Start(1000) - elif (self.stage == 2): - if (self.usingServer): - # See if the file has been uploaded yet and bring it here if so - queryServerForResults("threadoutput-" + self.ID) - self.timeoutCount = self.timeoutCount + 1 - if (self.timeoutCount >= serverTimeout): - self.tmrThread.Stop() - # If this is taking too long, maybe there's something wrong with the server - # Ask the user if they want to continue waiting or use the local daemon instead - dlg = wx.MessageDialog(self, "The server is taking a long time to respond. Continue to wait? Pressing No will run the calculations locally.", "Delayed Server Response", wx.YES_NO | wx.ICON_EXCLAMATION | wx.CENTRE) - if (dlg.ShowModal() == wx.ID_YES): - # Reset the counter - self.timeoutCount = 0 - else: - self.usingServer = False - self.timeoutCount = 0 - os.rename("threadinputtemp", "threadinput") - logInfo("Server took too long to respond so the local daemon was used") + pass + if (not(alreadythere)): + f = open("downloadwatch", "a") + f.write("COMPMODEL\t" + self.ID.strip() + "\t" + str(datetime.datetime.now().strftime("%A, %B %d - %I:%M:%S %p")) + "\t" + getServerName() + "\n") + f.close() + dlg = wx.MessageDialog(self, "InteractiveROSETTA is now watching the server for job ID " + self.ID.strip() + ". You will be notified when the package is available for download.", "Listening for Download", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + dlg.ShowModal() dlg.Destroy() - self.tmrThread.Start(1000) - # Read the output dumped by the child process (finally!) - if (os.path.isfile("threadoutput")): - self.tmrThread.Stop() - self.residue_E = [] - f = open("threadoutput", "r") - for aline in f: - if (aline[0:6] == "OUTPUT"): - pdbfile = aline.split("\t")[1].strip() - self.threadmodel = pdbfile - #self.dockView = pose_from_pdb(pdbfile) - elif (aline[0:6] == "ENERGY"): - if (aline.split()[1] == "total_score"): - # This is the scoretype line, row 0 in residue_E - self.residue_E.append(aline.split()[1:]) - else: - self.residue_E.append([]) - indx = len(self.residue_E) - 1 - for E in aline.split()[1:]: - self.residue_E[indx].append(float(E)) - f.close() - self.threadView = self.seqWin.pdbreader.get_structure("thread_view", self.threadmodel) - self.selectedModel = self.threadmodel - logInfo("Found threading output at threadoutput") - # Pop this message out of the queue - for i in range(0, len(self.seqWin.msgQueue)): - if (self.seqWin.msgQueue[i].find("Performing protein threading") >= 0): - self.seqWin.msgQueue.pop(i) - break - if (len(self.seqWin.msgQueue) > 0): - self.seqWin.labelMsg.SetLabel(self.seqWin.msgQueue[len(self.seqWin.msgQueue)-1]) - else: - self.seqWin.labelMsg.SetLabel("") - self.seqWin.labelMsg.SetFont(wx.Font(10, wx.DEFAULT, wx.ITALIC, wx.BOLD)) - self.seqWin.labelMsg.SetForegroundColour("#FFFFFF") - # Add these loop residues to the view menu so the user can look at the new loop - viewoptions = ["Whole View"] - ires = 1 - for ch in self.threadView[0]: - for residue in ch: - chain = ch.id - if (len(chain.strip()) == 0): - chain = "_" - seqpos = str(residue.id[1]) - resn = AA3to1(residue.resname) - viewoptions.append(chain + ":" + resn + seqpos) - ires = ires + 1 - self.viewMenu.Clear() - self.viewMenu.AppendItems(viewoptions) - self.viewMenu.SetSelection(0) - self.viewMenu.Enable() - # Add the nonzero scoretypes to the energy viewing list from the current score function - self.scoretypeMenu.Clear() - for scoretype in self.residue_E[0]: - try: - toAdd = scoretypes[str(scoretype)] - except: - toAdd = str(scoretype) - self.scoretypeMenu.Append(toAdd) - self.scoretypeMenu.Enable() - self.parent.GoBtn.Enable() - self.btnThread.Enable() - if (platform.system() == "Darwin"): - self.btnThread.SetBitmapLabel(bitmap=wx.Image(self.parent.parent.scriptdir + "/images/osx/btnThread_Finalize.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap()) - else: - self.btnThread.SetLabel("Finalize!") - self.buttonState = "Finalize!" - self.btnThread.SetToolTipString("Accept or reject protocol results") - os.remove("threadoutput") - # Load the docked pose as the "dock_view" model so the user can look at the results - self.cmd.load(self.threadmodel, "thread_view") - self.cmd.hide("everything", "model thread_view") - recolorEnergies(self.threadView, self.residue_E, "thread_view", self.scoretypeMenu.GetValue(), self.cmd) - self.focusView(self.viewMenu.GetValue(), "thread_view") - elif (os.path.isfile("errreport")): - # Something went wrong, tell the user about it - self.tmrThread.Stop() - self.recoverFromError() \ No newline at end of file + except: + dlg = wx.MessageDialog(self, "The comparative modeling job could not be sent to the server! Verify that you have an Internet connection and that the server is running.", "Server Could Not Be Reached", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + dlg.ShowModal() + dlg.Destroy() \ No newline at end of file diff --git a/InteractiveROSETTA/scripts/docking.py b/InteractiveROSETTA/scripts/docking.py index 16b709b..4a0a5f0 100644 --- a/InteractiveROSETTA/scripts/docking.py +++ b/InteractiveROSETTA/scripts/docking.py @@ -15,6 +15,102 @@ from threading import Thread from tools import * +class SettingsDialog(wx.Dialog): + def __init__(self, parent): + if (platform.system() != "Linux"): + wx.Dialog.__init__(self, parent, -1, "Constraint Default Settings", size=(330, 270)) + else: + wx.Dialog.__init__(self, parent, -1, "Constraint Default Settings", size=(330, 270)) + + # Structure label + self.lblTitle = wx.StaticText(self, -1, "Constraint Default Settings", (0, 10), (320, 30)) + self.lblTitle.SetFont(wx.Font(12, wx.DEFAULT, wx.ITALIC, wx.NORMAL)) + resizeTextControlForUNIX(self.lblTitle, 0, 320) + + ypos = 35 + if (platform.system() == "Windows"): + self.lblFunction = wx.StaticText(self, -1, "Function Type:", (0, ypos+23), (160, 20), wx.ALIGN_CENTRE) + self.lblFunction.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + elif (platform.system() == "Darwin"): + self.lblFunction = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblFunction.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(0, ypos+23), size=(160, 20)) + else: + self.lblFunction = wx.StaticText(self, -1, "Function Type:", (0, ypos+23), style=wx.ALIGN_CENTRE) + self.lblFunction.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + resizeTextControlForUNIX(self.lblFunction, 0, 160) + self.menuFunctions = wx.ComboBox(self, pos=(160, ypos+20), size=(160, 25), choices=["Harmonic", "Gaussian", "Bounded", "Sigmoid"], style=wx.CB_READONLY) + self.menuFunctions.SetToolTipString("List of supported constraint function types") + self.menuFunctions.SetStringSelection(parent.dFunction) + if (platform.system() == "Windows"): + self.lblIdealD = wx.StaticText(self, -1, "Ideal Distance (A):", (0, ypos+53), (200, 20), wx.ALIGN_CENTRE) + self.lblIdealD.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + elif (platform.system() == "Darwin"): + self.lblIdealD = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblIdealD.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(0, ypos+53), size=(200, 20)) + else: + self.lblIdealD = wx.StaticText(self, -1, "Ideal Distance (A):", (0, ypos+53), style=wx.ALIGN_CENTRE) + self.lblIdealD.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + resizeTextControlForUNIX(self.lblIdealD, 0, 200) + self.txtIdealD = wx.TextCtrl(self, -1, pos=(200, ypos+50), size=(120, 25)) + self.txtIdealD.SetValue(str(parent.dIdeal)) + self.txtIdealD.SetToolTipString("Ideal distance between the residue and its partner residue/chain") + if (platform.system() == "Windows"): + self.lblMaxD = wx.StaticText(self, -1, "Maximum Distance (A):", (0, ypos+83), (200, 20), wx.ALIGN_CENTRE) + self.lblMaxD.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + elif (platform.system() == "Darwin"): + self.lblMaxD = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblMaxD.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(0, ypos+83), size=(200, 20)) + else: + self.lblMaxD = wx.StaticText(self, -1, "Maximum Distance (A):", (0, ypos+83), style=wx.ALIGN_CENTRE) + self.lblMaxD.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + resizeTextControlForUNIX(self.lblMaxD, 0, 200) + self.txtMaxD = wx.TextCtrl(self, -1, pos=(200, ypos+80), size=(120, 25)) + self.txtMaxD.SetValue(str(parent.dMax)) + self.txtMaxD.SetToolTipString("Maximum distance between the residue and its partner residue/chain") + if (platform.system() == "Windows"): + self.lblMinD = wx.StaticText(self, -1, "Minimum Distance (A):", (0, ypos+113), (200, 20), wx.ALIGN_CENTRE) + self.lblMinD.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + elif (platform.system() == "Darwin"): + self.lblMinD = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblMinD.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(0, ypos+113), size=(200, 20)) + else: + self.lblMinD = wx.StaticText(self, -1, "Minimum Distance (A):", (0, ypos+113), style=wx.ALIGN_CENTRE) + self.lblMinD.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + resizeTextControlForUNIX(self.lblMinD, 0, 200) + self.txtMinD = wx.TextCtrl(self, -1, pos=(200, ypos+110), size=(120, 25)) + self.txtMinD.SetValue(str(parent.dMin)) + self.txtMinD.SetToolTipString("Minimum distance between the residue and its partner residue/chain") + if (platform.system() == "Windows"): + self.lblWeight = wx.StaticText(self, -1, "Weight:", (0, ypos+143), (200, 20), wx.ALIGN_CENTRE) + self.lblWeight.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + elif (platform.system() == "Darwin"): + self.lblWeight = wx.StaticBitmap(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/osx/lblWeight.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(0, ypos+143), size=(200, 20)) + else: + self.lblWeight = wx.StaticText(self, -1, "Weight:", (0, ypos+143), style=wx.ALIGN_CENTRE) + self.lblWeight.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + resizeTextControlForUNIX(self.lblWeight, 0, 200) + self.txtWeight = wx.TextCtrl(self, -1, pos=(200, ypos+140), size=(120, 25)) + self.txtWeight.SetValue(str(parent.dWeight)) + self.txtWeight.SetToolTipString("Relative weight of this constraint (constraints with higher weights are favored over those with lower weights)") + + # OK and Cancel buttons + self.btnOK = wx.Button(self, id=-1, label="OK", pos=(40, ypos+180), size=(100, 30)) + self.btnOK.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + self.btnOK.Bind(wx.EVT_BUTTON, self.okDialog) + self.btnOK.SetToolTipString("Confirm current indicated default settings") + self.btnCancel = wx.Button(self, id=-1, label="Cancel", pos=(180, ypos+180), size=(100, 30)) + self.btnCancel.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) + self.btnCancel.Bind(wx.EVT_BUTTON, self.cancelDialog) + self.btnCancel.SetToolTipString("Cancel this operation") + + # Center the dialog in the middle of the screen + self.SetPosition((wx.GetDisplaySize()[0]/2-150, wx.GetDisplaySize()[1]/2-150)) + + # Return codes, the main script knows how to interpret these + def okDialog(self, event): + self.SetReturnCode(wx.OK) + self.EndModal(wx.OK) + + def cancelDialog(self, event): + self.SetReturnCode(wx.CANCEL) + self.EndModal(wx.CANCEL) + class DockingPanel(wx.lib.scrolledpanel.ScrolledPanel): def __init__(self, parent, W, H): #if (platform.system() == "Windows"): @@ -247,6 +343,34 @@ def __init__(self, parent, W, H): self.btnSaveCST.SetToolTipString("Save the current constraints data to a real Rosetta constraints file") ypos = self.btnSaveCST.GetPosition()[1] + self.btnSaveCST.GetSize()[1] + 10 + self.btnDefaults = wx.BitmapButton(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/wrench.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(0, ypos-5), size=(25, 25)) + self.btnDefaults.Bind(wx.EVT_BUTTON, self.configureDefaults) + self.btnDefaults.SetToolTipString("Configure the default settings for docking constraints") + self.dFunction = "Bounded" + self.dMax = 12.0 + self.dMin = 6.0 + self.dIdeal = 9.0 + self.dWeight = 1.0 + # Try to read the default settings from the cfg file + goToSandbox() + try: + fin = open("docking.cfg", "r") + for aline in fin: + if (len(aline.strip()) == 0): + continue + if (aline.startswith("[FUNCTION]")): + self.dFunction = aline.split("\t")[1].strip() + elif (aline.startswith("[IDEAL]")): + self.dIdeal = float(aline.split("\t")[1].strip()) + elif (aline.startswith("[MAX]")): + self.dMax = float(aline.split("\t")[1].strip()) + elif (aline.startswith("[MIN]")): + self.dMin = float(aline.split("\t")[1].strip()) + elif (aline.startswith("[WEIGHT]")): + self.dWeight = float(aline.split("\t")[1].strip()) + fin.close() + except: + pass if (platform.system() == "Windows"): self.lblAdvanced = wx.StaticText(self, -1, "Advanced Options", (0, ypos), (320, 20), wx.ALIGN_CENTRE) self.lblAdvanced.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) @@ -653,6 +777,50 @@ def activate(self): self.selectedData.append([indx, r, seqpos, poseindx, chainID, chainoffset]) self.pruneConstraints() + def configureDefaults(self, event): + dlg = SettingsDialog(self) + if (dlg.ShowModal() == wx.OK): + # Update the default settings, ignoring invalid values + self.dFunction = dlg.menuFunctions.GetStringSelection() + try: + val = float(dlg.txtIdealD.GetValue()) + if (val <= 0): + raise Exception() + self.dIdeal = val + except: + pass + try: + val = float(dlg.txtMaxD.GetValue()) + if (val <= 0): + raise Exception() + self.dMax = val + except: + pass + try: + val = float(dlg.txtMinD.GetValue()) + if (val <= 0): + raise Exception() + self.dMin = val + except: + pass + try: + val = float(dlg.txtWeight.GetValue()) + if (val <= 0): + raise Exception() + self.dWeight = val + except: + pass + # Save these settings + goToSandbox() + fout = open("docking.cfg", "w") + fout.write("[FUNCTION]\t" + self.dFunction + "\n") + fout.write("[IDEAL]\t" + str(self.dIdeal) + "\n") + fout.write("[MAX]\t" + str(self.dMax) + "\n") + fout.write("[MIN]\t" + str(self.dMin) + "\n") + fout.write("[WEIGHT]\t" + str(self.dWeight) + "\n") + fout.close() + dlg.Destroy() + def showChain(self, ID): model = ID[0:len(ID)-2] chain = ID[len(ID)-1] @@ -1004,8 +1172,11 @@ def add(self, event): # break if (not(alreadyIn)): # Default parameters are added and the user can change these later - functionType = "Bounded" - functionArgs = "Max: 6, Min: 4, Weight: 1" + functionType = self.dFunction + if (functionType == "Bounded"): + functionArgs = "Max: " + str(self.dMax) + ", Min: " + str(self.dMin) + ", Weight: " + str(self.dWeight) + else: + functionArgs = "Ideal: " + str(self.dIdeal) + ", Weight: " + str(self.dWeight) self.insertConstraint(self.constraintType, thisID, "", functionType, functionArgs, "") self.updateConstraints() @@ -1259,12 +1430,12 @@ def functionMenuSelect(self, event): if (self.menuFunctions.GetStringSelection() == "Bounded"): self.txtIdealD.SetValue("0") self.txtIdealD.Disable() - self.txtMaxD.SetValue("12") + self.txtMaxD.SetValue(str(self.dMax)) self.txtMaxD.Enable() - self.txtMinD.SetValue("6") + self.txtMinD.SetValue(str(self.dMin)) self.txtMinD.Enable() else: - self.txtIdealD.SetValue("9") + self.txtIdealD.SetValue(str(self.dIdeal)) self.txtIdealD.Enable() self.txtMaxD.SetValue("0") self.txtMaxD.Disable() @@ -1658,6 +1829,8 @@ def saveConstraints(self, filename, convertChains=False): f = open(filename, "w") ambig_groups = {} tagno = 1 + # Ambiguous constraints have to come first before non-ambiguous ones, otherwise it + # crashes for no reason for [constraintType, residue, partner, functionType, functionArgs, group] in self.constraints: if (len(partner.strip()) == 0): # Ignore incomplete constraints when saving @@ -1673,7 +1846,7 @@ def saveConstraints(self, filename, convertChains=False): # Don't add entries for positions that do not have partners specified if (len(partner.strip()) == 0): continue - self.writeConstraint(f, constraintType, residue, partner, functionType, functionArgs, group, convertChains) + #self.writeConstraint(f, constraintType, residue, partner, functionType, functionArgs, group, convertChains) # Now write out the ambiguous constraints for grouped constraints for group in ambig_groups: # "group" is a key @@ -1683,6 +1856,17 @@ def saveConstraints(self, filename, convertChains=False): self.writeConstraint(f, constraintType, residue, partner, functionType, functionArgs, group, convertChains) if (len(ambig_groups[group]) > 1): f.write("END\n") + for [constraintType, residue, partner, functionType, functionArgs, group] in self.constraints: + if (len(partner.strip()) == 0): + # Ignore incomplete constraints when saving + continue + # Let's skip the grouped constraints + if (len(group.strip()) > 0): + continue + # Don't add entries for positions that do not have partners specified + if (len(partner.strip()) == 0): + continue + self.writeConstraint(f, constraintType, residue, partner, functionType, functionArgs, group, convertChains) f.close() def writeSinglePDB(self): diff --git a/InteractiveROSETTA/scripts/flexpepdock.py b/InteractiveROSETTA/scripts/flexpepdock.py index 57a076f..d15bf52 100644 --- a/InteractiveROSETTA/scripts/flexpepdock.py +++ b/InteractiveROSETTA/scripts/flexpepdock.py @@ -14,6 +14,7 @@ import numpy from threading import Thread from tools import * +from docking import SettingsDialog class FlexPepDockPanel(wx.lib.scrolledpanel.ScrolledPanel): def __init__(self, parent, W, H): @@ -251,6 +252,34 @@ def __init__(self, parent, W, H): self.btnSaveCST.SetToolTipString("Save the current constraints data to a real Rosetta constraints file") ypos = self.btnSaveCST.GetPosition()[1] + self.btnSaveCST.GetSize()[1] + 10 + self.btnDefaults = wx.BitmapButton(self, -1, wx.Image(self.parent.parent.scriptdir + "/images/wrench.png", wx.BITMAP_TYPE_PNG).ConvertToBitmap(), pos=(0, ypos-5), size=(25, 25)) + self.btnDefaults.Bind(wx.EVT_BUTTON, self.configureDefaults) + self.btnDefaults.SetToolTipString("Configure the default settings for docking constraints") + self.dFunction = "Bounded" + self.dMax = 12.0 + self.dMin = 6.0 + self.dIdeal = 9.0 + self.dWeight = 1.0 + # Try to read the default settings from the cfg file + goToSandbox() + try: + fin = open("flexpep.cfg", "r") + for aline in fin: + if (len(aline.strip()) == 0): + continue + if (aline.startswith("[FUNCTION]")): + self.dFunction = aline.split("\t")[1].strip() + elif (aline.startswith("[IDEAL]")): + self.dIdeal = float(aline.split("\t")[1].strip()) + elif (aline.startswith("[MAX]")): + self.dMax = float(aline.split("\t")[1].strip()) + elif (aline.startswith("[MIN]")): + self.dMin = float(aline.split("\t")[1].strip()) + elif (aline.startswith("[WEIGHT]")): + self.dWeight = float(aline.split("\t")[1].strip()) + fin.close() + except: + pass if (platform.system() == "Windows"): self.lblAdvanced = wx.StaticText(self, -1, "Advanced Options", (0, ypos), (320, 20), wx.ALIGN_CENTRE) self.lblAdvanced.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)) @@ -588,6 +617,50 @@ def activate(self): self.selectedData.append([indx, r, seqpos, poseindx, chainID, chainoffset]) self.pruneConstraints() + def configureDefaults(self, event): + dlg = SettingsDialog(self) + if (dlg.ShowModal() == wx.OK): + # Update the default settings, ignoring invalid values + self.dFunction = dlg.menuFunctions.GetStringSelection() + try: + val = float(dlg.txtIdealD.GetValue()) + if (val <= 0): + raise Exception() + self.dIdeal = val + except: + pass + try: + val = float(dlg.txtMaxD.GetValue()) + if (val <= 0): + raise Exception() + self.dMax = val + except: + pass + try: + val = float(dlg.txtMinD.GetValue()) + if (val <= 0): + raise Exception() + self.dMin = val + except: + pass + try: + val = float(dlg.txtWeight.GetValue()) + if (val <= 0): + raise Exception() + self.dWeight = val + except: + pass + # Save these settings + goToSandbox() + fout = open("flexpep.cfg", "w") + fout.write("[FUNCTION]\t" + self.dFunction + "\n") + fout.write("[IDEAL]\t" + str(self.dIdeal) + "\n") + fout.write("[MAX]\t" + str(self.dMax) + "\n") + fout.write("[MIN]\t" + str(self.dMin) + "\n") + fout.write("[WEIGHT]\t" + str(self.dWeight) + "\n") + fout.close() + dlg.Destroy() + def showChain(self, ID): model = ID[0:len(ID)-2] chain = ID[len(ID)-1] @@ -999,8 +1072,11 @@ def add(self, event): # break if (not(alreadyIn)): # Default parameters are added and the user can change these later - functionType = "Bounded" - functionArgs = "Max: 6, Min: 4, Weight: 1" + functionType = self.dFunction + if (functionType == "Bounded"): + functionArgs = "Max: " + str(self.dMax) + ", Min: " + str(self.dMin) + ", Weight: " + str(self.dWeight) + else: + functionArgs = "Ideal: " + str(self.dIdeal) + ", Weight: " + str(self.dWeight) self.insertConstraint(self.constraintType, thisID, "", functionType, functionArgs, "") self.updateConstraints() @@ -1254,12 +1330,12 @@ def functionMenuSelect(self, event): if (self.menuFunctions.GetStringSelection() == "Bounded"): self.txtIdealD.SetValue("0") self.txtIdealD.Disable() - self.txtMaxD.SetValue("12") + self.txtMaxD.SetValue(str(self.dMax)) self.txtMaxD.Enable() - self.txtMinD.SetValue("6") + self.txtMinD.SetValue(str(self.dMin)) self.txtMinD.Enable() else: - self.txtIdealD.SetValue("9") + self.txtIdealD.SetValue(str(self.dIdeal)) self.txtIdealD.Enable() self.txtMaxD.SetValue("0") self.txtMaxD.Disable() diff --git a/InteractiveROSETTA/scripts/sequence.py b/InteractiveROSETTA/scripts/sequence.py index e0d6d46..1002516 100644 --- a/InteractiveROSETTA/scripts/sequence.py +++ b/InteractiveROSETTA/scripts/sequence.py @@ -1017,7 +1017,7 @@ def keyPress(self, event): self.SeqViewer.ClearSelection() self.PyMOLUpdateTimer.Stop() self.PyMOLUpdateTimer.Start(100) - elif (event.ControlDown() and int(event.GetKeyCode()) == 3): + elif ((platform.system() == "Linux" and event.ControlDown() and int(event.GetKeyCode()) == 3) or (event.ControlDown() and int(event.GetKeyCode()) == ord("C"))): # Copy the current selection to the clipboard as FASTA data copystr = "" amISelected = [] @@ -1289,6 +1289,39 @@ def labelRClick(self, event): self.updateSeqViewer(rowToUpdate=k) self.regenerateLookupTable() + # Helper function for selecting the indicated residue + # Used by the comparative modeler + def selectNthResidue(self, r, indx, addToSelection=False, updateSelection=True): + count = 0 + c = -1 + for i in range(0, len(self.sequences[r])): + if (self.sequences[r][i] != "-"): + count += 1 + if (count >= indx): + c = i + break + if (c < 0): + return + self.SeqViewer.SelectBlock(r, c, r, c, addToSelection) + if (updateSelection): + self.selectUpdate(updatePyMOL=True) + # Possibly move the scroll position to bring this residue into view + scrollpos = self.SeqViewer.GetScrollPos(wx.HORIZONTAL) + x = self.SeqViewer.CellToRect(r, c)[0] + w = self.SeqViewer.GetSize()[0] - self.SeqViewer.GetRowLabelSize() - 20 + scrollunitconv = self.SeqViewer.GetScrollPixelsPerUnit()[0] + scrollpospx = scrollunitconv * scrollpos + if (x - scrollpospx >= w): + shift = int((float(x) - float(scrollpospx)) / float(w)) + totalscroll = int(scrollpospx + shift * w) + scrollunits = int(totalscroll / scrollunitconv) + self.SeqViewer.Scroll(scrollunits, 0) + elif (x - scrollpospx <= 0): + shift = int((float(scrollpospx) - float(x)) / float(w)) + 1 + totalscroll = int(scrollpospx - shift*w) + scrollunits = int(totalscroll / scrollunitconv) + self.SeqViewer.Scroll(max(0, scrollunits), 0) + # Helper function for selecting things in PyMOL using PyMOL's cmd API def selectInPyMOL(self, r, c, model, chain, res, resend, first): self.selectedResidues.append([r, c]) @@ -1993,7 +2026,7 @@ def PyMOLPDBLoad(self, dummy, pdbfile, showDialog="NoShow", flexiblePeptide=Fals if (currID == newID): taken = True break - # Sometimes I use special names for selections, and if the modelname is the same as + # Sometimes I use special names for selections, and if a modelname is the same as # these selections it can screw things up if (newID in ["temp", "sele", "seqsele", "params", "designed_view", "minimized_view"]): taken = True @@ -2377,6 +2410,16 @@ def saveClick(self, event): if (newmodel == ID.split("|")[0] and newmodel != model): taken = True break + # Sometimes I use special names for selections, and if a modelname is the same as + # these selections it can screw things up + if (newmodel in ["temp", "sele", "seqsele", "params", "designed_view", "minimized_view"]): + taken = True + if (newmodel == "flexpeptide" and not(flexiblePeptide)): + taken = True + # Replace whitespace with _ to avoid PyMOL issues + newmodel = newmodel.replace(" ", "_") + newmodel = newmodel.replace("\n", "_") + newmodel = newmodel.replace("\t", "_") if (taken): # Find a new ID that is not taken for i in range(2, 1000): @@ -3079,275 +3122,217 @@ def downloader(self, event): f.close() for i in range(0, len(self.activeJobs)): job = self.activeJobs[i] - if (job.startswith("FRAGMENT")): - ID = job.split("\t")[1].strip() - URL = "http://www.robetta.org/downloads/fragments/" + ID - downloadfiles = [] - try: - downloadpage = urllib2.urlopen(URL, timeout=1) - for aline in downloadpage: - # Look for the links - indx = aline.find("", indx+1) + 1 - linkend = aline.find("", indx+1) - if (not("Parent" in aline[linkbegin:linkend]) and not("Name" in aline[linkbegin:linkend])): - if (aline[linkbegin:linkend].endswith(".200_v1_3")): - downloadfiles.append(aline[linkbegin:linkend]) - elif (aline[linkbegin:linkend].endswith(".fasta")): - downloadfiles.append(aline[linkbegin:linkend]) - elif (aline[linkbegin:linkend].endswith(".psipred")): - downloadfiles.append(aline[linkbegin:linkend]) - elif (aline[linkbegin:linkend].endswith(".psipred_ss2")): - downloadfiles.append(aline[linkbegin:linkend]) + #elif (job.startswith("MSD") or job.startswith("ANTIBODY") or job.startswith("DOCK") or job.startswith("PMUTSCAN") or job.startswith("BACKRUB") or job.startswith("KIC") or job.startswith("FLEXPEP")): + jobtype = job.split("\t")[0] + ID = job.split("\t")[1].strip() + jobURL = job.split("\t")[3].strip() + if (job.startswith("MSD")): + packageext = ".msdar" + elif (job.startswith("PMUTSCAN")): + packageext = ".scan" + else: + packageext = ".ensb" + if (jobURL.lower().startswith("localhost")): + serverlocation = getServerName()[jobURL.find(":")+1:] + if (platform.system() == "Windows"): + resultsdir = serverlocation + "\\results\\" + ID + "\\" + filepath = resultsdir + "results" + packageext + else: + resultsdir = serverlocation + "/results/" + ID + "/" + filepath = resultsdir + "results" + packageext + else: + serverlocation = None + URL = jobURL + "/results/" + ID + "/results" + packageext + try: + if (serverlocation): + if (not(os.path.isfile(filepath))): + raise Exception() + if (jobtype == "MSD"): + dlg = wx.MessageDialog(self, "Your MSD package job ID " + ID + " is ready.", "MSD Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "ANTIBODY"): + dlg = wx.MessageDialog(self, "Your antibody package job ID " + ID + " is ready.", "Antibodies Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "COMPMODEL"): + dlg = wx.MessageDialog(self, "Your comparative modeling package job ID " + ID + " is ready.", "Structures Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "DOCK"): + dlg = wx.MessageDialog(self, "Your docking package job ID " + ID + " is ready.", "Docking Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "PMUTSCAN"): + dlg = wx.MessageDialog(self, "Your point mutant scanning job ID " + ID + " is ready.", "Point Mutants Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "BACKRUB"): + dlg = wx.MessageDialog(self, "Your backrub ensemble job ID " + ID + " is ready.", "Backrub Ensemble Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "KIC"): + dlg = wx.MessageDialog(self, "Your KIC ensemble job ID " + ID + " is ready.", "KIC Ensemble Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "FLEXPEP"): + dlg = wx.MessageDialog(self, "Your flexible peptide docking package job ID " + ID + " is ready.", "Flexible Peptide Docking Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + dlg.ShowModal() + dlg.Destroy() + os.rename(filepath, "results" + packageext) + else: + downloadpage = urllib2.urlopen(URL, timeout=1) # To make sure its there before display the dialog downloadpage.close() - dlg = wx.MessageDialog(self, "Your fragments package for job ID " + ID + " is ready.", "Fragments Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + if (jobtype == "MSD"): + dlg = wx.MessageDialog(self, "Your MSD package job ID " + ID + " is ready.", "MSD Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "ANTIBODY"): + dlg = wx.MessageDialog(self, "Your antibody package job ID " + ID + " is ready.", "Antibody Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "COMPMODEL"): + dlg = wx.MessageDialog(self, "Your comparative modeling package job ID " + ID + " is ready.", "Structure Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "DOCK"): + dlg = wx.MessageDialog(self, "Your docking package job ID " + ID + " is ready.", "Docking Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "PMUTSCAN"): + dlg = wx.MessageDialog(self, "Your point mutant scanning job ID " + ID + " is ready.", "Point Mutants Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "BACKRUB"): + dlg = wx.MessageDialog(self, "Your backrub ensemble job ID " + ID + " is ready.", "Backrub Ensemble Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "KIC"): + dlg = wx.MessageDialog(self, "Your KIC ensemble job ID " + ID + " is ready.", "KIC Ensemble Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) + elif (jobtype == "FLEXPEP"): + dlg = wx.MessageDialog(self, "Your flexible peptide docking package job ID " + ID + " is ready.", "Flexible Peptide Docking Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) dlg.ShowModal() dlg.Destroy() - while (True): + if (jobtype == "MSD"): + busyDlg = wx.BusyInfo("Downloading MSD archive, please wait...") + elif (jobtype == "ANTIBODY"): + busyDlg = wx.BusyInfo("Downloading antibody archive, please wait...") + elif (jobtype == "COMPMODEL"): + busyDlg = wx.BusyInfo("Downloading structure archive, please wait...") + elif (jobtype == "DOCK"): + busyDlg = wx.BusyInfo("Downloading docking archive, please wait...") + elif (jobtype == "PMUTSCAN"): + busyDlg = wx.BusyInfo("Downloading point mutant scan report, please wait...") + elif (jobtype == "BACKRUB"): + busyDlg = wx.BusyInfo("Downloading backrub archive, please wait...") + elif (jobtype == "KIC"): + busyDlg = wx.BusyInfo("Downloading KIC archive, please wait...") + elif (jobtype == "FLEXPEP"): + busyDlg = wx.BusyInfo("Downloading flexpep archive, please wait...") + (oldfilename, info) = urllib.urlretrieve(URL, "results" + packageext) + busyDlg.Destroy() + del busyDlg + while (True): + if (jobtype == "MSD"): dlg = wx.FileDialog( - self, message="Save the Frag File", + self, message="Save the MSD package", defaultDir=self.cwd, defaultFile=ID, - wildcard="Frag Files (*.frag)|*.frag", + wildcard="MSD Archives (*.msdar)|*.msdar", style=wx.SAVE | wx.CHANGE_DIR) - if (dlg.ShowModal() == wx.ID_OK): - if (platform.system() == "Darwin"): - paths = [dlg.GetPath()] - else: - paths = dlg.GetPaths() - # Change cwd to the last opened file - if (platform.system() == "Windows"): - lastDirIndx = paths[len(paths)-1].rfind("\\") + elif (jobtype == "ANTIBODY"): + dlg = wx.FileDialog( + self, message="Save the antibody package", + defaultDir=self.cwd, + defaultFile=ID, + wildcard="Ensemble Archives (*.ensb)|*.ensb", + style=wx.SAVE | wx.CHANGE_DIR) + elif (jobtype == "COMPMODEL"): + dlg = wx.FileDialog( + self, message="Save the structure package", + defaultDir=self.cwd, + defaultFile=ID, + wildcard="Ensemble Archives (*.ensb)|*.ensb", + style=wx.SAVE | wx.CHANGE_DIR) + elif (jobtype == "DOCK"): + dlg = wx.FileDialog( + self, message="Save the docking package", + defaultDir=self.cwd, + defaultFile=ID, + wildcard="Ensemble Archives (*.ensb)|*.ensb", + style=wx.SAVE | wx.CHANGE_DIR) + elif (jobtype == "PMUTSCAN"): + dlg = wx.FileDialog( + self, message="Save the scan file", + defaultDir=self.cwd, + defaultFile=ID, + wildcard="Point Mutant Scan (*.scan)|*.scan", + style=wx.SAVE | wx.CHANGE_DIR) + elif (jobtype == "BACKRUB"): + dlg = wx.FileDialog( + self, message="Save the backrub package", + defaultDir=self.cwd, + defaultFile=ID, + wildcard="Ensemble Archives (*.ensb)|*.ensb", + style=wx.SAVE | wx.CHANGE_DIR) + elif (jobtype == "KIC"): + dlg = wx.FileDialog( + self, message="Save the KIC package", + defaultDir=self.cwd, + defaultFile=ID, + wildcard="Ensemble Archives (*.ensb)|*.ensb", + style=wx.SAVE | wx.CHANGE_DIR) + elif (jobtype == "FLEXPEP"): + dlg = wx.FileDialog( + self, message="Save the flexpep package", + defaultDir=self.cwd, + defaultFile=ID, + wildcard="Ensemble Archives (*.ensb)|*.ensb", + style=wx.SAVE | wx.CHANGE_DIR) + if (dlg.ShowModal() == wx.ID_OK): + if (platform.system() == "Darwin"): + paths = [dlg.GetPath()] + else: + paths = dlg.GetPaths() + # Change cwd to the last opened file + if (platform.system() == "Windows"): + lastDirIndx = paths[len(paths)-1].rfind("\\") + else: + lastDirIndx = paths[len(paths)-1].rfind("/") + self.cwd = str(paths[len(paths)-1][0:lastDirIndx]) + self.saveWindowData(None) + filename = str(paths[0]).split(packageext)[0] + packageext + # Does it exist already? If so, ask if the user really wants to overwrite it + if (os.path.isfile(filename)): + dlg2 = wx.MessageDialog(self, "The file " + filename + " already exists. Overwrite it?", "Filename Already Exists", wx.YES_NO | wx.ICON_QUESTION | wx.CENTRE) + if (dlg2.ShowModal() == wx.ID_NO): + dlg2.Destroy() + logInfo("Cancelled save operation due to filename already existing") + continue else: - lastDirIndx = paths[len(paths)-1].rfind("/") - self.cwd = str(paths[len(paths)-1][0:lastDirIndx]) - self.saveWindowData(None) - # Load the PDBs into PyMOL - filename = str(paths[0]).split(".frag")[0] + ".frag" - # Does it exist already? If so, ask if the user really wants to overwrite it - if (os.path.isfile(filename)): - dlg2 = wx.MessageDialog(self, "The file " + filename + " already exists. Overwrite it?", "Filename Already Exists", wx.YES_NO | wx.ICON_QUESTION | wx.CENTRE) - if (dlg2.ShowModal() == wx.ID_NO): - dlg2.Destroy() - logInfo("Cancelled save operation due to filename already existing") - continue - dlg2.Destroy() - break - busyDlg = wx.BusyInfo("Downloading fragment file, please wait...") - gzipfile = gzip.open(str(filename), "wb") - for downloadfile in downloadfiles: - serverdata = urllib2.urlopen(URL + "/" + downloadfile) - gzipfile.write("BEGIN\t" + downloadfile + "\n") - gzipfile.writelines(serverdata) - gzipfile.write("END\t" + downloadfile + "\n") - serverdata.close() + os.remove(str(filename)) + dlg2.Destroy() + break + goToSandbox() + os.rename("results" + packageext, str(filename)) + if (jobtype != "PMUTSCAN"): + # Unpackage the files + gzipfile = gzip.open(str(filename), "rb") + prefix = filename.split(packageext)[0] + readingData = False + for aline in gzipfile: + if (aline.startswith("BEGIN PDB")): + if (jobtype == "MSD"): + if (platform.system() == "Windows"): + f = open(self.cwd + "\\" + aline.split()[len(aline.split())-1].strip(), "w") + else: + f = open(self.cwd + "/" + aline.split()[len(aline.split())-1].strip(), "w") + elif (jobtype in ["ANTIBODY", "DOCK", "BACKRUB", "KIC", "FLEXPEP", "COMPMODEL"]): + indx = aline[aline.rfind("_")+1:].strip() + f = open(prefix + "_" + indx, "w") + readingData = True + elif (aline.startswith("END PDB")): + f.close() + readingData = False + elif (readingData): + f.write(aline.strip() + "\n") gzipfile.close() - busyDlg = None - changed = True - removeJob[i] = True - except: - # Not there yet - pass - elif (job.startswith("MSD") or job.startswith("ANTIBODY") or job.startswith("DOCK") or job.startswith("PMUTSCAN") or job.startswith("BACKRUB") or job.startswith("KIC") or job.startswith("FLEXPEP")): - jobtype = job.split("\t")[0] - ID = job.split("\t")[1].strip() - jobURL = job.split("\t")[3].strip() - if (job.startswith("MSD")): - packageext = ".msdar" - elif (job.startswith("PMUTSCAN")): - packageext = ".scan" - else: - packageext = ".ensb" - if (jobURL.lower().startswith("localhost")): - serverlocation = getServerName()[jobURL.find(":")+1:] - if (platform.system() == "Windows"): - resultsdir = serverlocation + "\\results\\" + ID + "\\" - filepath = resultsdir + "results" + packageext - else: - resultsdir = serverlocation + "/results/" + ID + "/" - filepath = resultsdir + "results" + packageext + changed = True + removeJob[i] = True + except: + # Not there yet + pass + URL = jobURL + "/results/" + ID + "/errreport" + try: + # Look for an error file + if (serverlocation): + downloadpage = open(resultsdir + "errreport") else: - serverlocation = None - URL = jobURL + "/results/" + ID + "/results" + packageext - try: - if (serverlocation): - if (not(os.path.isfile(filepath))): - raise Exception() - if (jobtype == "MSD"): - dlg = wx.MessageDialog(self, "Your MSD package job ID " + ID + " is ready.", "MSD Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - elif (jobtype == "ANTIBODY"): - dlg = wx.MessageDialog(self, "Your antibody package job ID " + ID + " is ready.", "Antibodies Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - elif (jobtype == "DOCK"): - dlg = wx.MessageDialog(self, "Your docking package job ID " + ID + " is ready.", "Docking Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - elif (jobtype == "PMUTSCAN"): - dlg = wx.MessageDialog(self, "Your point mutant scanning job ID " + ID + " is ready.", "Point Mutants Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - elif (jobtype == "BACKRUB"): - dlg = wx.MessageDialog(self, "Your backrub ensemble job ID " + ID + " is ready.", "Backrub Ensemble Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - elif (jobtype == "KIC"): - dlg = wx.MessageDialog(self, "Your KIC ensemble job ID " + ID + " is ready.", "KIC Ensemble Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - elif (jobtype == "FLEXPEP"): - dlg = wx.MessageDialog(self, "Your flexible peptide docking package job ID " + ID + " is ready.", "Flexible Peptide Docking Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - dlg.ShowModal() - dlg.Destroy() - os.rename(filepath, "results" + packageext) - else: - downloadpage = urllib2.urlopen(URL, timeout=1) # To make sure its there before display the dialog - downloadpage.close() - if (jobtype == "MSD"): - dlg = wx.MessageDialog(self, "Your MSD package job ID " + ID + " is ready.", "MSD Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - elif (jobtype == "ANTIBODY"): - dlg = wx.MessageDialog(self, "Your antibody package job ID " + ID + " is ready.", "Antibody Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - elif (jobtype == "DOCK"): - dlg = wx.MessageDialog(self, "Your docking package job ID " + ID + " is ready.", "Docking Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - elif (jobtype == "PMUTSCAN"): - dlg = wx.MessageDialog(self, "Your point mutant scanning job ID " + ID + " is ready.", "Point Mutants Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - elif (jobtype == "BACKRUB"): - dlg = wx.MessageDialog(self, "Your backrub ensemble job ID " + ID + " is ready.", "Backrub Ensemble Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - elif (jobtype == "KIC"): - dlg = wx.MessageDialog(self, "Your KIC ensemble job ID " + ID + " is ready.", "KIC Ensemble Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - elif (jobtype == "FLEXPEP"): - dlg = wx.MessageDialog(self, "Your flexible peptide docking package job ID " + ID + " is ready.", "Flexible Peptide Docking Download Ready", wx.OK | wx.ICON_EXCLAMATION | wx.CENTRE) - dlg.ShowModal() - dlg.Destroy() - if (jobtype == "MSD"): - busyDlg = wx.BusyInfo("Downloading MSD archive, please wait...") - elif (jobtype == "ANTIBODY"): - busyDlg = wx.BusyInfo("Downloading antibody archive, please wait...") - elif (jobtype == "DOCK"): - busyDlg = wx.BusyInfo("Downloading docking archive, please wait...") - elif (jobtype == "PMUTSCAN"): - busyDlg = wx.BusyInfo("Downloading point mutant scan report, please wait...") - elif (jobtype == "BACKRUB"): - busyDlg = wx.BusyInfo("Downloading backrub archive, please wait...") - elif (jobtype == "KIC"): - busyDlg = wx.BusyInfo("Downloading KIC archive, please wait...") - elif (jobtype == "FLEXPEP"): - busyDlg = wx.BusyInfo("Downloading flexpep archive, please wait...") - (oldfilename, info) = urllib.urlretrieve(URL, "results" + packageext) - busyDlg.Destroy() - del busyDlg - while (True): - if (jobtype == "MSD"): - dlg = wx.FileDialog( - self, message="Save the MSD package", - defaultDir=self.cwd, - defaultFile=ID, - wildcard="MSD Archives (*.msdar)|*.msdar", - style=wx.SAVE | wx.CHANGE_DIR) - elif (jobtype == "ANTIBODY"): - dlg = wx.FileDialog( - self, message="Save the antibody package", - defaultDir=self.cwd, - defaultFile=ID, - wildcard="Ensemble Archives (*.ensb)|*.ensb", - style=wx.SAVE | wx.CHANGE_DIR) - elif (jobtype == "DOCK"): - dlg = wx.FileDialog( - self, message="Save the docking package", - defaultDir=self.cwd, - defaultFile=ID, - wildcard="Ensemble Archives (*.ensb)|*.ensb", - style=wx.SAVE | wx.CHANGE_DIR) - elif (jobtype == "PMUTSCAN"): - dlg = wx.FileDialog( - self, message="Save the scan file", - defaultDir=self.cwd, - defaultFile=ID, - wildcard="Point Mutant Scan (*.scan)|*.scan", - style=wx.SAVE | wx.CHANGE_DIR) - elif (jobtype == "BACKRUB"): - dlg = wx.FileDialog( - self, message="Save the backrub package", - defaultDir=self.cwd, - defaultFile=ID, - wildcard="Ensemble Archives (*.ensb)|*.ensb", - style=wx.SAVE | wx.CHANGE_DIR) - elif (jobtype == "KIC"): - dlg = wx.FileDialog( - self, message="Save the KIC package", - defaultDir=self.cwd, - defaultFile=ID, - wildcard="Ensemble Archives (*.ensb)|*.ensb", - style=wx.SAVE | wx.CHANGE_DIR) - elif (jobtype == "FLEXPEP"): - dlg = wx.FileDialog( - self, message="Save the flexpep package", - defaultDir=self.cwd, - defaultFile=ID, - wildcard="Ensemble Archives (*.ensb)|*.ensb", - style=wx.SAVE | wx.CHANGE_DIR) - if (dlg.ShowModal() == wx.ID_OK): - if (platform.system() == "Darwin"): - paths = [dlg.GetPath()] - else: - paths = dlg.GetPaths() - # Change cwd to the last opened file - if (platform.system() == "Windows"): - lastDirIndx = paths[len(paths)-1].rfind("\\") - else: - lastDirIndx = paths[len(paths)-1].rfind("/") - self.cwd = str(paths[len(paths)-1][0:lastDirIndx]) - self.saveWindowData(None) - filename = str(paths[0]).split(packageext)[0] + packageext - # Does it exist already? If so, ask if the user really wants to overwrite it - if (os.path.isfile(filename)): - dlg2 = wx.MessageDialog(self, "The file " + filename + " already exists. Overwrite it?", "Filename Already Exists", wx.YES_NO | wx.ICON_QUESTION | wx.CENTRE) - if (dlg2.ShowModal() == wx.ID_NO): - dlg2.Destroy() - logInfo("Cancelled save operation due to filename already existing") - continue - else: - os.remove(str(filename)) - dlg2.Destroy() - break - goToSandbox() - os.rename("results" + packageext, str(filename)) - if (jobtype != "PMUTSCAN"): - # Unpackage the files - gzipfile = gzip.open(str(filename), "rb") - prefix = filename.split(packageext)[0] - readingData = False - for aline in gzipfile: - if (aline.startswith("BEGIN PDB")): - if (jobtype == "MSD"): - if (platform.system() == "Windows"): - f = open(self.cwd + "\\" + aline.split()[len(aline.split())-1].strip(), "w") - else: - f = open(self.cwd + "/" + aline.split()[len(aline.split())-1].strip(), "w") - elif (jobtype == "ANTIBODY" or jobtype == "DOCK" or jobtype == "BACKRUB" or jobtype == "KIC" or jobtype == "FLEXPEP"): - indx = aline[aline.rfind("_")+1:].strip() - f = open(prefix + "_" + indx, "w") - readingData = True - elif (aline.startswith("END PDB")): - f.close() - readingData = False - elif (readingData): - f.write(aline.strip() + "\n") - gzipfile.close() - changed = True - removeJob[i] = True - except: - # Not there yet - pass - URL = jobURL + "/results/" + ID + "/errreport" - try: - # Look for an error file - if (serverlocation): - downloadpage = open(resultsdir + "errreport") - else: - downloadpage = urllib2.urlopen(URL, timeout=1) # To make sure its there before display the dialog - f = open("errreport", "w") - for aline in downloadpage: - f.write(aline.strip() + "\n") - downloadpage.close() - f.close() - self.recoverFromError(jobtype) - changed = True - removeJob[i] = True - except: - pass + downloadpage = urllib2.urlopen(URL, timeout=1) # To make sure its there before display the dialog + f = open("errreport", "w") + for aline in downloadpage: + f.write(aline.strip() + "\n") + downloadpage.close() + f.close() + self.recoverFromError(jobtype) + changed = True + removeJob[i] = True + except: + pass # If a change happened, update the "downloadwatch" file to take the completed jobs out if (changed): goToSandbox() diff --git a/InteractiveROSETTA/scripts/tools.py b/InteractiveROSETTA/scripts/tools.py index 637382d..1965228 100644 --- a/InteractiveROSETTA/scripts/tools.py +++ b/InteractiveROSETTA/scripts/tools.py @@ -1341,12 +1341,12 @@ def goToSandbox(extra=""): os.chdir(homedir + "/InteractiveROSETTA" + extra) def AA3to1(resn): - indx3 = "ALA CYS ASP GLU PHE GLY HIS ILE LYS LEU MET ASN PRO GLN ARG SER THR VAL TRP TYR HOH ".find(resn) + indx3 = "ALA CYS ASP GLU PHE GLY HIS ILE LYS LEU MET ASN PRO GLN ARG SER THR VAL TRP TYR HOH ADE CYT GUA THY RAD RCY RGU URA ".find(resn) if (indx3 < 0): return "Z" else: indx = indx3 / 4 - return "ACDEFGHIKLMNPQRSTVWYO"[indx] + return "ACDEFGHIKLMNPQRSTVWYOacgtacgu"[indx] def resizeTextControlForUNIX(widget, leftbound, width): # The centering feature doesn't seem to work on UNIX, so in order to center we have to @@ -1575,6 +1575,7 @@ def appendScorefxnParamsInfoToFile(filename, weightsfile): goToSandbox("params") paramsfiles = glob.glob("*.params") for paramsfile in paramsfiles: + # Do not send over nucleotides, they apparently already get imported by default f.write("PARAMS\t" + paramsfile.strip() + "\n") f.write("BEGIN PARAMS DATA\n") f2 = open(paramsfile.strip(), "r") @@ -1706,7 +1707,8 @@ def queryServerForResults(outputfile): def getRecognizedTypes(): # Returns a list of 3 letter codes that will be recognized by Rosetta recognized = ["ALA", "CYS", "ASP", "GLU", "PHE", "GLY", "HIS", "ILE", "LYS", "LEU", "MET", "ASN", - "PRO", "GLN", "ARG", "SER", "THR", "VAL", "TRP", "TYR", "HIE", "HID"] + "PRO", "GLN", "ARG", "SER", "THR", "VAL", "TRP", "TYR", "HIE", "HID", "ADE", "CYT", + "GUA", "THY", "RAD", "RCY", "RGU", "URA"] if (platform.system() == "Windows"): # Windows has all the metal ions by default recognized.extend(["CA", "FE2", "FE", "K", "MG", "MN", "NA", "ZN"]) @@ -1722,9 +1724,13 @@ def cleanPDB(pdbfile): # This function will look for and remove duplicate atoms # It will permanently modify the PDB that the user loaded # This shouldn't cause problems for other programs though + # I am also going to give blank chain IDs a value because it + # is causing too much trouble with some of the Rosetta protocols + # to handle blank chain IDs data = [] taken_nums = {} num_mapping = {} + takenIDs = "" # Sometimes there are PDBs that have multiple residues with the same residue index # BioPython drops these, but it can lead to all kinds of problems later on # So I will keep a record of the backbone atoms of the current residue and if we encounter @@ -1734,7 +1740,9 @@ def cleanPDB(pdbfile): f = open(pdbfile.strip(), "r") curr_res = " 0" for aline in f: - if (aline.startswith("ATOM") or aline.startswith("HETATM")): + if ((aline.startswith("ATOM") or aline.startswith("HETATM")) and not aline[21] in takenIDs): + takenIDs += aline[21] + if ((aline.startswith("ATOM") or aline.startswith("HETATM")) and isAA(aline[17:20])): res = aline[22:27] # Includes residue indx + the optional alternate letter if (res[0:4] != curr_res[0:4]): # New residue indx altlocs_taken = res[4] # Reset the taken altlocs @@ -1788,12 +1796,30 @@ def cleanPDB(pdbfile): aline = aline[0:22] + num_mapping[chain+res] + " " + aline[27:] #data.append(aline.strip()) #else: - data.append(aline.strip()) + # Change nucleic acid strings to what Rosetta expects + if (aline[17:20] == " DA"): + data.append(aline[0:17] + "ADE" + aline[20:]) + elif (aline[17:20] == " DC"): + data.append(aline[0:17] + "CYT" + aline[20:]) + elif (aline[17:20] == " DG"): + data.append(aline[0:17] + "GUA" + aline[20:]) + elif (aline[17:20] == " DT"): + data.append(aline[0:17] + "THY" + aline[20:]) + else: + data.append(aline) f.close() # Now write the updated data out + blankID = "" + for char in "ABCDEFGHIJKLMNOPQRSTUVWXYZ": + if (char not in takenIDs): + blankID = char + break f = open(pdbfile.strip(), "w") for aline in data: - f.write(aline + "\n") + if ((aline.startswith("ATOM") or aline.startswith("HETATM")) and aline[21] == " "): + f.write(aline[0:21] + blankID + aline[22:]) + else: + f.write(aline) f.close() def fixPyMOLSave(pdbfile): @@ -1893,4 +1919,11 @@ def deleteInputFiles(): # Remove the sandbox PDBs tempfiles = glob.glob("*.pdb") for tempfile in tempfiles: - os.remove(tempfile) \ No newline at end of file + os.remove(tempfile) + +def isAA(resn): + if (len(resn) == 3 and resn in "ALA CYS ASP GLU PHE GLY HIS ILE LYS LEU MET ASN PRO GLN ARG SER THR VAL TRP TYR "): + return True + elif (len(resn) == 1 and resn in "ACDEFGHIKLMNPQRSTVWY"): + return True + return False \ No newline at end of file diff --git a/InteractiveROSETTA/server/backrub.py b/InteractiveROSETTA/server/backrub.py index 9771264..7553bae 100644 --- a/InteractiveROSETTA/server/backrub.py +++ b/InteractiveROSETTA/server/backrub.py @@ -57,7 +57,7 @@ init(extra_options="-ignore_unrecognized_res -mute all") scorefxn = create_score_function("talaris2013") # Get the params files -paramsfiles = glob.glob("*.params") +paramsfiles = glob.glob("*.fa.params") paramsstr = " -extra_res_fa " if (len(paramsfiles) == 0): paramsstr = "" diff --git a/InteractiveROSETTA/server/cgi-bin/jobupload.cgi b/InteractiveROSETTA/server/cgi-bin/jobupload.cgi index e1be907..f60d828 100755 --- a/InteractiveROSETTA/server/cgi-bin/jobupload.cgi +++ b/InteractiveROSETTA/server/cgi-bin/jobupload.cgi @@ -39,7 +39,7 @@ try: elif (aline.find("Content") < 0): filedata.append(aline.strip()) # Make sure the filename is something we'd be expecting to see from InteractiveROSETTA - if (not(filename in ["minimizeinput", "designinput", "scoreinput", "rotamerinput", "coarsekicinput", "msdinput", "testinput", "coarsedockinput", "antibodyinput", "scaninput", "killinput", "backrubinput", "flexpepinput"])): + if (not(filename in ["minimizeinput", "designinput", "scoreinput", "rotamerinput", "coarsekicinput", "msdinput", "testinput", "coarsedockinput", "antibodyinput", "scaninput", "killinput", "backrubinput", "flexpepinput", "threadinput"])): raise Exception() if (filename == "testinput"): print "InteractiveROSETTA Upload Successful" diff --git a/InteractiveROSETTA/server/daemon_server.py b/InteractiveROSETTA/server/daemon_server.py index 78e5b13..65e14ca 100755 --- a/InteractiveROSETTA/server/daemon_server.py +++ b/InteractiveROSETTA/server/daemon_server.py @@ -166,7 +166,7 @@ def initializeRosetta(inputfile): f2.write(aline.strip() + "\n") f.close() paramsstr = "" - paramsFiles = glob.glob(hostname + "-*.params") + paramsFiles = glob.glob(hostname + "-*.fa.params") for params in paramsFiles: paramsstr = paramsstr + params.strip() + " " if (len(paramsstr) > 0): @@ -945,6 +945,22 @@ def doFlexPep(inputfile): # The Python script will handle everything from here # Get back to where we were os.chdir("../..") + +def doThread(inputfile): + # Make a new results folder and unpack the data there + try: + os.mkdir("results/" + ID) + except: + shutil.rmtree("results/" + ID, ignore_errors=True) + os.mkdir("results/" + ID) + os.chdir("results/" + ID) + # Move the input file here + os.rename("../../" + inputfile, inputfile.split("-")[1]) + # Submit it to the queue + sub = subprocess.Popen(["python", "../../rosetta_submit.py", "thread", ID]) + # The Python script will handle everything from here + # Get back to where we were + os.chdir("../..") def writeError(msg, inputfile="None-"): # Open a file and write out the error message so the main GUI can tell the user what happened @@ -1150,6 +1166,13 @@ def writeError(msg, inputfile="None-"): inputfile = "jobfiles/" + hostname.replace("-", "") + "-flexpepinput-" + ID print "Daemon starting flexible peptide docking job..." doFlexPep(inputfile) + elif (inputfile.startswith("jobfiles/" + hostname + "-threadinput")): + if ("-" in hostname): + # If the hostname has - in it, it will screw up the splitting later on, so fix it here + os.rename(inputfile, "jobfiles/" + hostname.replace("-", "") + "-threadinput-" + ID) + inputfile = "jobfiles/" + hostname.replace("-", "") + "-threadinput-" + ID + print "Daemon starting comparative modeling job..." + doThread(inputfile) elif (inputfile.startswith("jobfiles/" + hostname + "-killinput")): fin = open(inputfile, "r") filedata = fin.readlines() diff --git a/InteractiveROSETTA/server/gen-sequence-profile.pl b/InteractiveROSETTA/server/gen-sequence-profile.pl new file mode 100644 index 0000000..fbf494a --- /dev/null +++ b/InteractiveROSETTA/server/gen-sequence-profile.pl @@ -0,0 +1,240 @@ +#!/usr/bin/perl -w + +$num_args = $#ARGV + 1; +if ($num_args != 3) { + print "\nUsage: gen-sequence-profile.pl \n"; + print " : The FASTA file for the protein's whose profile will be generated\n"; + print " : This is the output of blastpgp, which is a legacy BLAST executable\n"; + print " Ex. blastpgp -i input.fasta -j 2 -d nr.15 -C checkpoint.pssm\n"; + print " The file checkpoint.pssm corresponds to \n"; + print " : The name of the output file\n"; + exit; +} + +my $checkpoint=$ARGV[1]; +my $fasta=$ARGV[0]; +my $output=$ARGV[2]; + +my $sequence = read_fasta( $fasta ); +print "Sequence: $sequence"; +# parse & fortran-ify the checkpoint matrix. +my @checkpoint_matrix; +@checkpoint_matrix = &parse_checkpoint_file("$checkpoint"); +@checkpoint_matrix = + &finish_checkpoint_matrix( $sequence, @checkpoint_matrix ); +&write_checkpoint_file( "$output", $sequence, + @checkpoint_matrix ); + +sub read_fasta { + my $fn = shift; + + open( SEQFILE, $fn ) or die "Error opening fasta file $fn!\n"; + my $has_comment = 0; + my $eof; + my $seq = ''; + while ( my $line = ) { + $eof = $line; + $line =~ s/\s//g; + if ( $line =~ /^>/ ) { + $has_comment = 1; + } + else { + chomp $line; + $seq .= $line; + } + } + + my $has_eof = ( $eof =~ /\n$/ ); + ( $has_comment && $has_eof ) + or die + "fasta file (given $fn) must have a comment and end with a new line!\n"; + close SEQFILE or die $!; + + return $seq; +} + +## parse_checkpoint_file -- parses a PSI-BLAST binary checkpoint file. +# +# args: filename of checkpoint file. +# rets: N x 20 array containing checkpoint weight values, where N +# is the size of the protein that BLAST thought it saw... + +sub parse_checkpoint_file { + my $filename = shift; + my $buf; + my $seqlen; + my $seqstr; + my $i; + my $j; + my @aa_order = split( //, 'ACDEFGHIKLMNPQRSTVWY' ); + my @altschul_mapping = + ( 0, 4, 3, 6, 13, 7, 8, 9, 11, 10, 12, 2, 14, 5, 1, 15, 16, 19, 17, 18 ); + my @w; + my @output; + + open( INPUT, $filename ) or die("Couldn't open $filename for reading.\n"); + + read( INPUT, $buf, 4 ) or die("Couldn't read $filename!\n"); + $seqlen = unpack( "i", $buf ); + + print "Sequence length: $seqlen"; + + read( INPUT, $buf, $seqlen ) or die("Premature end: $filename.\n"); + $seqstr = unpack( "a$seqlen", $buf ); + + for ( $i = 0 ; $i < $seqlen ; ++$i ) { + read( INPUT, $buf, 160 ) or die("Premature end: $filename, line: $i\n"); + @w = unpack( "d20", $buf ); + + for ( $j = 0 ; $j < 20 ; ++$j ) { + $output[$i][$j] = $w[ $altschul_mapping[$j] ]; + } + } + + return @output; +} + +## finish_checkpoint_matrix -- "finishes" the parsed PSI-BLAST checkpoint matrix, +## by adding pseudo-counts to any empty columns. +# +# args: 1) sequence string 2) array returned by parse_checkpoint_file +# rets: "finished" array. suitable for printing, framing, etc. + +sub finish_checkpoint_matrix { + my ( $s, @matrix ) = @_; + my @sequence = split( //, $s ); + my $i; + my $j; + my $sum; + my @words; + my @b62; + my @blos_aa = + ( 0, 14, 11, 2, 1, 13, 3, 5, 6, 7, 9, 8, 10, 4, 12, 15, 16, 18, 19, 17 ); + + my %aaNum = ( + A => 0, + C => 1, + D => 2, + E => 3, + F => 4, + G => 5, + H => 6, + I => 7, + K => 8, + L => 9, + M => 10, + N => 11, + P => 12, + Q => 13, + R => 14, + S => 15, + T => 16, + V => 17, + W => 18, + Y => 19, + X => 0 + ); + + ( length($s) == scalar(@matrix) ) + or die("Length mismatch between sequence and checkpoint file!\n"); + + my $blosum62 = <= 62 + A R N D C Q E G H I L K M F P S T W Y V +0.0215 +0.0023 0.0178 +0.0019 0.0020 0.0141 +0.0022 0.0016 0.0037 0.0213 +0.0016 0.0004 0.0004 0.0004 0.0119 +0.0019 0.0025 0.0015 0.0016 0.0003 0.0073 +0.0030 0.0027 0.0022 0.0049 0.0004 0.0035 0.0161 +0.0058 0.0017 0.0029 0.0025 0.0008 0.0014 0.0019 0.0378 +0.0011 0.0012 0.0014 0.0010 0.0002 0.0010 0.0014 0.0010 0.0093 +0.0032 0.0012 0.0010 0.0012 0.0011 0.0009 0.0012 0.0014 0.0006 0.0184 +0.0044 0.0024 0.0014 0.0015 0.0016 0.0016 0.0020 0.0021 0.0010 0.0114 0.0371 +0.0033 0.0062 0.0024 0.0024 0.0005 0.0031 0.0041 0.0025 0.0012 0.0016 0.0025 0.0161 +0.0013 0.0008 0.0005 0.0005 0.0004 0.0007 0.0007 0.0007 0.0004 0.0025 0.0049 0.0009 0.0040 +0.0016 0.0009 0.0008 0.0008 0.0005 0.0005 0.0009 0.0012 0.0008 0.0030 0.0054 0.0009 0.0012 0.0183 +0.0022 0.0010 0.0009 0.0012 0.0004 0.0008 0.0014 0.0014 0.0005 0.0010 0.0014 0.0016 0.0004 0.0005 0.0191 +0.0063 0.0023 0.0031 0.0028 0.0010 0.0019 0.0030 0.0038 0.0011 0.0017 0.0024 0.0031 0.0009 0.0012 0.0017 0.0126 +0.0037 0.0018 0.0022 0.0019 0.0009 0.0014 0.0020 0.0022 0.0007 0.0027 0.0033 0.0023 0.0010 0.0012 0.0014 0.0047 0.0125 +0.0004 0.0003 0.0002 0.0002 0.0001 0.0002 0.0003 0.0004 0.0002 0.0004 0.0007 0.0003 0.0002 0.0008 0.0001 0.0003 0.0003 0.0065 +0.0013 0.0009 0.0007 0.0006 0.0003 0.0007 0.0009 0.0008 0.0015 0.0014 0.0022 0.0010 0.0006 0.0042 0.0005 0.0010 0.0009 0.0009 0.0102 +0.0051 0.0016 0.0012 0.0013 0.0014 0.0012 0.0017 0.0018 0.0006 0.0120 0.0095 0.0019 0.0023 0.0026 0.0012 0.0024 0.0036 0.0004 0.0015 0.0196 +BLOSUM + + $i = 0; + my @blosum62 = split( /\n/, $blosum62 ); + + # read/build the blosum matrix + foreach my $blosumline (@blosum62) { + next if ( $blosumline !~ /^\d/ ); + chomp $blosumline; + @words = split( /\s/, $blosumline ); + + for ( $j = 0 ; $j <= $#words ; ++$j ) { + $b62[ $blos_aa[$i] ][ $blos_aa[$j] ] = $words[$j]; + $b62[ $blos_aa[$j] ][ $blos_aa[$i] ] = $words[$j]; + } + + ++$i; + } + + # normalize the blosum matrix so that each row sums to 1.0 + for ( $i = 0 ; $i < 20 ; ++$i ) { + $sum = 0.0; + + for ( $j = 0 ; $j < 20 ; ++$j ) { + $sum += $b62[$i][$j]; + } + + for ( $j = 0 ; $j < 20 ; ++$j ) { + $b62[$i][$j] = ( $b62[$i][$j] / $sum ); + } + } + + # substitute appropriate blosum row for 0 rows + for ( $i = 0 ; $i <= $#matrix ; ++$i ) { + $sum = 0; + + for ( $j = 0 ; $j < 20 ; ++$j ) { + $sum += $matrix[$i][$j]; + } + + if ( $sum == 0 ) { + for ( $j = 0 ; $j < 20 ; ++$j ) { + $matrix[$i][$j] = $b62[ $aaNum{ $sequence[$i] } ][$j]; + } + } + } + + return @matrix; +} + +sub write_checkpoint_file { + my ( $filename, $sequence, @matrix ) = @_; + my $row; + my $col; + my @seq = split( //, $sequence ); + + open( OUTPUT, ">$filename" ); + + die("Length mismatch between sequence and checkpoint matrix!\n") + unless ( length($sequence) == scalar(@matrix) ); + + print OUTPUT scalar(@matrix), "\n"; + + for ( $row = 0 ; $row <= $#matrix ; ++$row ) { + print OUTPUT "$seq[$row] "; + for ( $col = 0 ; $col < 20 ; ++$col ) { + printf OUTPUT "%6.4f ", $matrix[$row][$col]; + } + print OUTPUT "\n"; + } + + print OUTPUT "END"; + + close(OUTPUT); +} diff --git a/InteractiveROSETTA/server/maintain.csh b/InteractiveROSETTA/server/maintain.csh index 5fed6bd..ccbba7e 100755 --- a/InteractiveROSETTA/server/maintain.csh +++ b/InteractiveROSETTA/server/maintain.csh @@ -45,6 +45,14 @@ end foreach OLDFILE (`find $IROSETTA_HOME/results/* -maxdepth 0 -mmin +5 -type f`) rm -f $OLDFILE end +# Sometimes the mutexes get abandoned, and then the whole server hangs until the sysadmin +# manually deletes them. This deletes mutexes more than 10 minutes old +foreach OLDFILE (`find $IROSETTA_HOME/backend_query -maxdepth 0 -mmin +10 -type f`) + rm -f $OLDFILE +end +foreach OLDFILE (`find $IROSETTA_HOME/backend_query -maxdepth 0 -mmin +10 -type f`) + rm -f $OLDFILE +end # Clean up some more junk foreach OLDFILE (`find $IROSETTA_HOME/*.pdb -maxdepth 0 -mmin +20 -type f`) rm -f $OLDFILE @@ -109,4 +117,16 @@ foreach DIR (`ls -d -- results/*/`) echo "Pending" endif endif + if (-e $DIR/flexpepinput) then + if (-e $DIR/frag.out) then + echo "Generating fragments..." > $DIR/status + else + echo "Pending" + endif + if (-e $DIR/flexpep.out) then + set MODELS = `ls $DIR/*.pdb | wc -l` + set MODELS = `expr $MODELS - 1` + echo $MODELS" Models Completed" > $DIR/status + endif + endif end \ No newline at end of file diff --git a/InteractiveROSETTA/server/rosetta_submit.py b/InteractiveROSETTA/server/rosetta_submit.py index 6b2f2b2..a0a2e07 100755 --- a/InteractiveROSETTA/server/rosetta_submit.py +++ b/InteractiveROSETTA/server/rosetta_submit.py @@ -36,6 +36,8 @@ antibody_home = "/usr/local/rosetta/tools/antibody" # Location of the fragment tools package fragment_tools = "/usr/local/rosetta/tools/fragment_tools" +# Location of the setup_RosettaCM.py script +cm_scripts = "/usr/local/rosetta/tools/protein_tools/scripts" # ==================================================================================================================== def AA3to1(resn): @@ -301,6 +303,7 @@ def setupKIC(): fin = open("coarsekicinput", "r") nstruct = 1 loopdata = [] + readingData = False for aline in fin: if (aline[0:7] == "PDBFILE"): pdbfile = aline.split("\t")[1].strip() @@ -493,7 +496,7 @@ def doFlexPep(): res, output = commands.getstatusoutput(commandline) if (res): print "ERROR: blastpgp failed!" - exit() + print output # Now we have to use Rosetta's script to convert the binary checkpoint.pssm to a text # file that can be used for sequence profiles commandline = "perl ../../gen-sequence-profile.pl peptide.fasta checkpoint.pssm frags.chk" @@ -501,14 +504,14 @@ def doFlexPep(): res, output = commands.getstatusoutput(commandline) if (res): print "ERROR: gen-sequence-profile.pl failed!" - exit() + print output # Now run psipred to get the secondary structure prediction commandline = "runpsipred_single peptide.fasta" print commandline res, output = commands.getstatusoutput(commandline) if (res): print "ERROR: PSIPRED failed!" - exit() + print output # Now generate a simple weighting scheme for fragment selection fout = open("simple.wghts", "w") fout.write("# score name priority wght max_allowed extras\n") @@ -567,7 +570,7 @@ def doFlexPep(): res, output = commands.getstatusoutput(commandline) if (res): print "ERROR: Could not shift the frag files!" - exit() + print output # Now that we have the fragments, we can run flexpepdock # Generate the new frags file fout = open("flags", "w") @@ -656,6 +659,178 @@ def doFlexPep(): outfile = "final_flexpep_%4.4i.pdb" % (i+1) os.system("cp " + pdblist[i] + " " + outfile) +def doThread(): + # Unpack the input files + fin = open("threadinput", "r") + readingData = False + templates = [] + targaligns = [] + tempaligns = [] + for aline in fin: + if (aline.startswith("FASTA")): + FASTAseq = aline.split("\t")[1].strip() + elif (aline.startswith("PDBFILE")): + pdbfile = aline.split("\t")[1].strip() + templates.append(pdbfile) + fout = open(pdbfile, "w") + elif (aline.startswith("BEGIN PDB DATA")): + readingData = True + elif (aline.startswith("END PDB DATA")): + fout.close() + readingData = False + elif (aline.startswith("TARGALIGN")): + targaligns.append(aline.split("\t")[1].strip()) + elif (aline.startswith("TEMPALIGN")): + tempaligns.append(aline.split("\t")[1].strip()) + elif (aline.startswith("NMODELS")): + nstruct = int(aline.split("\t")[1]) + elif (readingData): + fout.write(aline) + fin.close() + # Let's get the FASTA file + fout = open("target.fasta", "w") + fout.write("> Target\n" + FASTAseq.strip() + "\n") + fout.close() + # First we have to generate fragments for the comparative modeler + # Now we have to run PSIBLAST to get a position specific matrix to generate the sequence + # profile for fragment selections + commandline = "blastpgp -i target.fasta -j 2 -d nr.15 -C checkpoint.pssm" + print commandline + res, output = commands.getstatusoutput(commandline) + if (res): + print "ERROR: blastpgp failed!" + print output + # Now we have to use Rosetta's script to convert the binary checkpoint.pssm to a text + # file that can be used for sequence profiles + commandline = "perl ../../gen-sequence-profile.pl target.fasta checkpoint.pssm frags.chk" + print commandline + res, output = commands.getstatusoutput(commandline) + if (res): + print "ERROR: gen-sequence-profile.pl failed!" + print output + # Now run psipred to get the secondary structure prediction + commandline = "runpsipred_single target.fasta" + print commandline + res, output = commands.getstatusoutput(commandline) + if (res): + print "ERROR: PSIPRED failed!" + print output + # Now generate a simple weighting scheme for fragment selection + fout = open("simple.wghts", "w") + fout.write("# score name priority wght max_allowed extras\n") + fout.write("SecondarySimilarity 350 1.0 - psipred\n") + fout.write("RamaScore 150 2.0 - psipred\n") + fout.write("ProfileScoreL1 200 2.0 -\n") + fout.write("SequenceIdentity 100 1.0 -") # No newline here otherwise you get a duplicate!!! + fout.close() + # Setup and run fragment generation + fout = open("flags", "w") + fout.write("-database " + rosetta_db + "\n") + fout.write("-in::file::vall " + fragment_tools + "/vall.apr24.2008.extended.gz\n") + fout.write("-in::file::fasta target.fasta\n") + fout.write("-in::file::checkpoint frags.chk\n") + fout.write("-frags::ss_pred target.ss2 psipred\n") + fout.write("-frags::scoring::config simple.wghts\n") + fout.write("-frags::bounded_protocol\n") + fout.write("-frags::frag_sizes 3 5 9\n") + fout.write("-frags::n_candidates 200\n") + fout.write("-frags::n_frags 200\n") + fout.write("-out::file::frag_prefix frags\n") + fout.write("-frags::describe_fragments frags.fsc\n") + fout.close() + if (separateMPI_master): + command = "ssh " + MPI_master + " \"cd " + iRosetta_home + "/results/" + jobID.strip() + "; (" + mpiexec + " " + hostfile_arg + " hostfile_" + jobID.strip() + " " + numproc_arg + " 1 " + rosetta_bin + "/fragment_picker.mpi.linuxgccrelease @flags > frag.out) >& frag.err\"" + else: + command = "cd " + iRosetta_home + "/results/" + jobID.strip() + "; (" + mpiexec + " " + hostfile_arg + " hostfile_" + jobID.strip() + " " + numproc_arg + " 1 " + rosetta_bin + "/fragment_picker.mpi.linuxgccrelease @flags > frag.out) >& frag.err" + print command + p = Popen(args=command, stdout=PIPE, shell=True) + (out, err) = p.communicate() + # Okay, now we need to set up a multiple sequence alignment for the comparative modeler + # The alignments as they are now are correct, but the target sequences may have gaps in + # different places so all we have to do is line up all the target sequences and keep the + # template sequences aligned to the same residues + indx = 0 + while (True): + getout = True + for i in range(0, len(targaligns)): + if (indx < len(targaligns[i])): + getout = False + break + if (getout): + break + # Do we have a gap at this index in any of the target alignments? + havegap = False + for i in range(0, len(targaligns)): + if (indx >= len(targaligns[i]) or targaligns[i][indx] == "-"): + havegap = True + if (havegap): + # Yes, we do. Add one into each target sequence that does not have a gap + # and also add a gap to their partner alignments + for i in range(0, len(targaligns)): + if (indx >= len(targaligns[i])): + targaligns[i] += "-" + tempaligns[i] += "-" + elif (targaligns[i][indx] != "-"): + targaligns[i] = targaligns[i][0:indx] + "-" + targaligns[i][indx:] + tempaligns[i] = tempaligns[i][0:indx] + "-" + tempaligns[i][indx:] + indx += 1 + # Write the alignment out as a FASTA file + fout = open("comparative.aln", "w") + fout.write("> Target\n" + targaligns[0].strip() + "\n\n") + for i in range(0, len(tempaligns)): + fout.write("> " + templates[i].split(".pdb")[0] + "\n" + tempaligns[i].strip() + "\n\n") + fout.close() + # Okay, now let's run the setup_RosettaCM.py script to generate some input files for CM + commandline = "python " + cm_scripts + "/setup_RosettaCM.py --fasta target.fasta " + \ + "--alignment comparative.aln --alignment_format fasta --rosetta_bin " + rosetta_bin + " --templates " + for pdbfile in templates: + commandline += pdbfile.strip() + " " + print commandline + # For some reason the script below sometimes does not generate the appropriate pdbfiles + # Let's help it along now + try: + os.mkdir("rosetta_cm") + except: + pass + for template in templates: + shutil.copy(template, "rosetta_cm/" + template.split(".pdb")[0] + "_201.pdb") # This seems to be what it looks for + res, output = commands.getstatusoutput(commandline) + if (res): + print "ERROR: setup_RosettaCM.py failed!" + print output + # This generates a folder called "rosetta_cm" that contains most of our input files + os.chdir("rosetta_cm") + # The flags file does not have the frags files in it, so let's add them + fout = open("flags", "a") + fout.write("-frag3 ../frags.200.3mers\n") + fout.write("-frag5 ../frags.200.5mers\n") + fout.write("-frag9 ../frags.200.9mers\n") + fout.close() + # There's also a score function issue, apparently cart_bonded and pro_close cannot be used + # together, so turn off pro_close (https://www.rosettacommons.org/content/multiple-homology-modelling, pose #28) + data = [] + fin = open("stage3_rlx.wts", "r") + for aline in fin: + if ("pro_close" not in aline): + data.append(aline) + fin.close() + fout = open("stage3_rlx.wts", "w") + for aline in data: + fout.write(aline) + fout.close() + # Now we can run rosettaCM + if (separateMPI_master): + command = "ssh " + MPI_master + " \"cd " + iRosetta_home + "/results/" + jobID.strip() + "/rosetta_cm; (" + mpiexec + " " + hostfile_arg + " ../hostfile_" + jobID.strip() + " " + numproc_arg + " " + str(cpus) + " " + rosetta_bin + "/rosetta_scripts.mpi.linuxgccrelease @flags -database " + rosetta_db + " -nstruct " + str(nstruct) + " > cm.out) >& cm.err\"" + else: + command = "cd " + iRosetta_home + "/results/" + jobID.strip() + "/rosetta_cm; (" + mpiexec + " " + hostfile_arg + " ../hostfile_" + jobID.strip() + " " + numproc_arg + " " + str(cpus) + " " + rosetta_bin + "/rosetta_scripts.mpi.linuxgccrelease @flags -database " + rosetta_db + " -nstruct " + str(nstruct) + " > cm.out) >& cm.err" + print command + p = Popen(args=command, stdout=PIPE, shell=True) + (out, err) = p.communicate() + # Move the output files back out of this directory + for i in range(0, nstruct): + os.rename("S_%4.4i.pdb" % (i+1), "../final_cm_%4.4i.pdb" % (i+1)) + os.chdir("..") + # This script is used by InteractiveROSETTA to submit uploaded jobs to the C++ Rosetta, and then packages them up into # files that the client GUI can access remotely # Please note that this script is called by daemon_server.py @@ -792,6 +967,13 @@ def doFlexPep(): nmodels = int(aline.split("\t")[1]) break fin.close() + elif (protocol == "thread"): + fin = open("threadinput", "r") + for aline in fin: + if (aline.startswith("NMODELS")): + nmodels = int(aline.split("\t")[1]) + break + fin.close() elif (protocol == "kic"): fin = open("coarsekicinput", "r") for aline in fin: @@ -816,7 +998,7 @@ def doFlexPep(): elif (protocol == "flexpep"): fin = open("flexpepinput", "r") for aline in fin: - if (aline.startswith("RETURNMODELS")): + if (aline.startswith("DECOYS")): nmodels = int(aline.split("\t")[1]) break fin.close() @@ -855,7 +1037,7 @@ def doFlexPep(): if (float(load_1min) < 0.5 * float(nproc)): cpus_allocated = cpus_allocated + slots selected_hosts.append([hostname, slots]) - if (protocol in ["antibody", "dock", "pmutscan", "backrub", "kic", "flexpep"]): + if (protocol in ["antibody", "dock", "pmutscan", "backrub", "kic", "flexpep", "thread"]): if (cpus_allocated >= nmodels): cpus = nmodels runnable = True @@ -869,7 +1051,7 @@ def doFlexPep(): else: runnable = False os.remove(iRosetta_home + "/backend_query") - if (protocol in ["antibody", "dock", "pmutscan", "backrub", "kic"]): + if (protocol in ["antibody", "dock", "pmutscan", "backrub", "kic", "thread"]): # Ideally we want one processor per model, but if we have at least mincpus then let's go for it if (not(runnable) and cpus_allocated >= mincpus): cpus = cpus_allocated @@ -1083,7 +1265,9 @@ def doFlexPep(): command = "cd " + iRosetta_home + "/results/" + jobID.strip() + "; (" + mpiexec + " " + hostfile_arg + " hostfile_" + jobID.strip() + " " + numproc_arg + " " + str(cpus) + " " + rosetta_bin + "/mpi_msd.mpi.linuxgccrelease @flags > msd.out) >& msd.err" elif (protocol == "flexpep"): doFlexPep() - if (protocol not in ["dock", "flexpep"]): + elif (protocol == "thread"): + doThread() + if (protocol not in ["dock", "flexpep", "thread"]): print command p = Popen(args=command, stdout=PIPE, shell=True) (out, err) = p.communicate() @@ -1187,6 +1371,30 @@ def doFlexPep(): f.write(errmsg) f.close() exit() +elif (protocol == "thread"): + # Did we crash? The answer is yes then we did not get the required number of output models + crashed = False + errmsg = "" + try: + f = open("cm.err", "r") + for aline in f: + errmsg = errmsg + aline.strip() + "\n" + f.close() + except: + f = open("frag.err", "r") + for aline in f: + errmsg = errmsg + aline.strip() + "\n" + f.close() + # Sometimes warnings get outputted to the error file, so we can't know if an error really happening + # simply by checking to see if dock.err has content in it + outputfiles = glob.glob("final_cm_????.pdb") + if (len(outputfiles) == 0): + crashed = True + if (crashed): + f = open("errreport", "w") + f.write(errmsg) + f.close() + exit() elif (protocol == "backrub"): # Did we crash? The answer is yes then we did not get the required number of output models crashed = False