Source code for schrodinger.application.prime.gui.analyze_energy

from collections import OrderedDict

import schrodinger
from schrodinger.Qt import QtGui
from schrodinger.Qt import QtWidgets
from schrodinger.structutils import analyze
from schrodinger.ui.qt import widgetmixins
from schrodinger.ui.qt.appframework2 import af2
from schrodinger.ui.qt.appframework2 import settings

from .ui import analyze_energy_ui
from .ui import environment_options_ui

maestro = schrodinger.get_maestro()
try:
    from schrodinger.application.prime.packages import Prime
    # PXerror is imported here so it can be reimported in modules calling
    # AnalyzeEnergyWidget.runSingleStruc(), as it will be raised for failed jobs
    from schrodinger.application.prime.packages.PXutil import PXerror
except ImportError:
    Prime = None
    PXerror = None


[docs]class AnalyzeEnergyWidget(widgetmixins.MessageBoxMixin, QtWidgets.QWidget): SOLVATION = OrderedDict( (("VSGB", "vsgb"), ("Vacuum", "vac"), ("Chloroform", "chloroform")))
[docs] def __init__(self, parent=None): super(AnalyzeEnergyWidget, self).__init__(parent) self.ui = analyze_energy_ui.Ui_Form() self.ui.setupUi(self) self.setup()
[docs] def setup(self): self.options_dialog = AnalyzeEnergyOptions(self) self.ui.solvation_combo.addItemsFromDict(self.SOLVATION) self.ui.options_btn.clicked.connect(self.options_dialog.open)
[docs] def reset(self): self.ui.solvation_combo.setCurrentIndex(0) self.ui.force_field_selector.update() self.options_dialog.reset()
def _checkProtPrep(self, struc): """ Make sure that the protein contains hydrogens. If it doesn't, tell the user to run the Protein Preparation Wizard. :param struc: The structure to check :type struc: `schrodinger.structure.Structure` :return: True if the protein contains hydrogens. False otherwise. :rtype: bool """ if analyze.hydrogens_present(struc): return True msg = ("Force field check failed. Please make sure the structure has " "hydrogens and valid bond bond orders and atom charges. Would " "you like to use the Protein Preparation Wizard to clean up " "your structure?") if self.question(msg, title="Error", yes_text="Open PrepWizard"): maestro.command("pythonrunbuiltin prepwizard_gui.panel") return False def _checkMembrane(self, struc): """ Make sure that there is membrane data present if the user has specified the membrane environment. :param struc: The structure to check :type struc: `schrodinger.structure.Structure` :return: False if a membrane environment is selected but the structure does not contain membrane data. True otherwise. :rtype: bool """ key = self.options_dialog.MEMBRANE_ENVIRON if self.options_dialog.getAliasedValue(key): prop_suffixes = ((i, j) for i in (1, 2) for j in "xyz") prop_names = ("r_psp_Memb%i_%s" % (i, j) for i, j in prop_suffixes) return all(prop in struc.property for prop in prop_names) else: return True
[docs] def validateWorkspace(self): """ Make sure that the workspace structure is acceptable input for energy analysis. If it isn't, display an error dialog explaining why. :return: True if the structure is acceptable. False otherwise. :rtype: bool """ status = self._workspaceValidation() if isinstance(status, bool): return status elif isinstance(status, str): self.error(status) return False
[docs] def sanitizeCustomOPLSDir(self): """ Sanitize the forcefield selector's custom OPLS dir choice allowing it to be reset to not using one if it could not be 'sanitized'. :return: whether the validated custom OPLS dir should be used. :rtype: bool """ ffs = self.ui.force_field_selector return ffs.sanitizeCustomOPLSDir(allow_default_dialog=True)
[docs] def getCustomOPLSDir(self): """ Return OPLSDIR suitable for passing to jobcontrol through -OPLSDIR or None if usage of a custom directory is not selected. :rtype: str :returns: string of OPLS dir or None custom forcefield not selected """ ffs = self.ui.force_field_selector return ffs.getCustomOPLSDIR()
def _workspaceValidation(self): """ Make sure that the workspace structure is acceptable input for energy analysis :return: If the structure is acceptable, return True. If the structure is not acceptable, returns either: An error message to display to the user or False if nothing needs to be displayed to the user :rtype: bool or str """ try: struc = maestro.get_included_entry() except RuntimeError: return "Only a single entry may be included in the workspace" if not self._checkProtPrep(struc): return False elif not self._checkMembrane(struc): return ("The workspace structure is missing the required membrane " "properties.") else: return True
[docs] def runSingleStruc(self, struc): """ Run energy analysis on the specified structure and load the result into the project table :param struc: The structure to analyze :type struc: `schrodinger.structure.Structure` :raise `PXerror`: If the energy analysis fails """ arg_list = self.getArgList() prime_out = Prime.run_prime("analyze_energy", "ENERGY", struc, arg_list) new_struc = prime_out[0] proj = maestro.project_table_get() row = proj.importStructure(new_struc, wsreplace=True) row.title += " - Prime analyzed"
def _getArgs(self): """ Get the appropriate Prime arguments :return: A dictionary of Prime arguments :rtype: dict """ dlg = self.options_dialog dlg_settings = dlg.getAliasedSettings() yesno = lambda x: "yes" if x else "no" dielectric = dlg_settings[dlg.DIELECTRIC] crystal = dlg_settings[dlg.CRYSTAL_ENVIRON] membrane = dlg_settings[dlg.MEMBRANE_ENVIRON] solvation = self.ui.solvation_combo.currentData() ff = self.ui.force_field_selector.getSelectionForceField() ff = ff.replace("_", "") args = { "USE_CRYSTAL_SYMMETRY": yesno(crystal), "USE_RANDOM_SEED": "no", "OPLS_VERSION": ff, "EXT_DIEL": str(dielectric), "USE_MEMBRANE": yesno(membrane), "HOST": "localhost" } if solvation != "vsgb": args["SGB_MOD"] = solvation return args
[docs] def getArgList(self): """ :return: the list of arguments for a `Prime.run_prime` call """ args = self._getArgs() arg_list = [] list(map(arg_list.extend, args.items())) return arg_list
[docs]class AnalyzeEnergyOptions(settings.BaseOptionsPanel): DEFAULT_ENVIRON = "default_environ" MEMBRANE_ENVIRON = "membrane_environ" CRYSTAL_ENVIRON = "crystal_environ" DIELECTRIC = "dielectric"
[docs] def setPanelOptions(self): super(AnalyzeEnergyOptions, self).setPanelOptions() self.title = "Analyze Energy - Options" self.ui = environment_options_ui.Ui_Form() self.help_topic = 'PRIME_ANALYZE_ENERGY_OPTIONS'
[docs] def setup(self): super(AnalyzeEnergyOptions, self).setup() self.ui.set_up_membrane_btn.clicked.connect(self.setUpMembrane) self.ui.dielectric_le.setValidator(QtGui.QDoubleValidator(self)) self.setAlias(self.DEFAULT_ENVIRON, self.ui.default_rb) self.setAlias(self.MEMBRANE_ENVIRON, self.ui.membrane_rb) self.setAlias(self.CRYSTAL_ENVIRON, self.ui.unit_cell_rb) self.setAlias(self.DIELECTRIC, self.ui.dielectric_le)
@af2.validator() def checkDielectric(self): """ Make sure that the dielectric line edit has a valid value """ if self.ui.dielectric_le.hasAcceptableInput(): return True else: return (False, "Invalid dielectric value.")
[docs] def setUpMembrane(self): """ Launch the Membrane GUI panel in response to the user clicking the "Set Up Membrane" button """ maestro.command("pythonrunbuiltin membrane_gui.panel")