Source code for schrodinger.application.phase.create_xvol

"""
Phase driver for the Develop Common Pharmacophore Hypotheses (DHCP) workflow.

Copyright Schrodinger LLC, All Rights Reserved.
"""

import os
import subprocess

from schrodinger.application.phase import hypothesis
from schrodinger.infra import phase
from schrodinger.utils import fileutils
from schrodinger.utils import log

# Logging
logger = log.get_output_logger(__file__)

# Schrodinger env variable
SCHRODINGER_UTIL = os.path.join(os.getenv("SCHRODINGER"), "utilities")
XVOL_SHELL_DRIVER = os.path.join(SCHRODINGER_UTIL, "create_xvolShell")
XVOL_CLASH_DRIVER = os.path.join(SCHRODINGER_UTIL, "create_xvolClash")
XVOL_RECEPTOR_DRIVER = os.path.join(SCHRODINGER_UTIL, "create_xvolReceptor")


[docs]class ExcludedVolumeGenerator(object): """ Class to create excluded volumes for a given PhaseHypothesis. """
[docs] def __init__(self, base_hypothesis): """ Initialize by creating a temp copy of the base hypothesis. :param base_hypothesis: :type base_hypothesis: str or `PhpHypoAdaptor` """ self.base_hypo = base_hypothesis
def _getSettings(self, settings_inputconfig): """ Initialize the class, updating the PhaseHypothesisInputConfig mode, validating the settings, and creating a member namedtuple. :param settings_inputconfig: Phase derived InputConfig instance :type settings_inputconfig: `PhaseHypothesisInputConfig` """ if not settings_inputconfig: return None #settings_inputconfig.setInputMode(phase_input.InputMode.create_xvol) settings_inputconfig.validateInput() return settings_inputconfig.asNamedTuple()
[docs] def createExcludedVolumeShell(self, active_sts, settings): """ Runs the excluded volume shell creation for given active structures. create_xvolShell -hypo <hypo> -ref <actives> [options] :param active_sts: structures to build excluded volume shell around :type active_sts: list of `structure.Structure` :param settings: calculation settings :type settings: `PhaseHypothesisInputConfig` :return: Excluded volume based on active structure shell :rtype: `phase.PhpExclVol` """ xvol_settings = self._getSettings(settings) if not xvol_settings.excluded_volume_mode == "shell": raise RuntimeError("Unexpected excluded volume mode.") args = [] if xvol_settings.min_surface_to_volume_distance: buff_dist = xvol_settings.min_surface_to_volume_distance args.extend(["-buff", buff_dist]) if xvol_settings.excluded_volume_sphere_radii: args.extend(["-grid", xvol_settings.excluded_volume_sphere_radii]) if xvol_settings.append_excluded_volumes: args.append("-append") # If using a reference structure, create and run with TempStructureFile if active_sts: with fileutils.TempStructureFile(active_sts) as ref_filename: args = ["-ref", ref_filename] + args xvol = self._runCreateXvolCommand(XVOL_SHELL_DRIVER, args) # Otherwise, run the driver with no structure file else: xvol = self._runCreateXvolCommand(XVOL_SHELL_DRIVER, args) return xvol
[docs] def createExcludedVolumeClash(self, active_sts, inactive_sts, settings): """ Runs the excluded volume clash creation for a given set of active and inactive structures. create_xvolClash -hypo <hypo> -pos <actives> -neg <inactives> [options] :param active_sts: active structures :type active_sts: list of `structure.Structure` :param inactive_sts: inactive structures :type inactive_sts: list of `structure.Structure` :param settings: calculation settings :type settings: `PhaseHypothesisInputConfig` :return: Excluded volume based on active/inactive clash :rtype: `phase.PhpExclVol` """ xvol_settings = self._getSettings(settings) if not xvol_settings.excluded_volume_mode == "clash": raise RuntimeError("Unexpected excluded volume mode.") args = [] if xvol_settings.min_surface_to_volume_distance: buff_dist = xvol_settings.min_surface_to_volume_distance args.extend(["-buff", buff_dist]) if xvol_settings.min_num_inactives_with_clash: args.extend(["-freq", xvol_settings.min_num_inactives_with_clash]) if xvol_settings.excluded_volume_sphere_radii: args.extend(["-grid", xvol_settings.excluded_volume_sphere_radii]) if xvol_settings.append_excluded_volumes: args.append("-append") with fileutils.TempStructureFile(active_sts) as actives_file, \ fileutils.TempStructureFile(inactive_sts) as inactives_file: args = ["-pos", actives_file, "-neg", inactives_file] + args xvol = self._runCreateXvolCommand(XVOL_CLASH_DRIVER, args) return xvol
[docs] def createExcludedVolumeReceptor(self, receptor_st, settings): """ Runs the excluded volume creation for a given receptor create_xvolReceptor -hypo <hypo> -receptor <receptor> [options] :param receptor_st: receptor structure :type receptor_st: `structure.Structure` :param settings: calculation settings :type settings: `PhaseHypothesisInputConfig` :return: Excluded volume based on active/inactive clash :rtype: `phase.PhpExclVol` """ xvol_settings = self._getSettings(settings) if not xvol_settings.excluded_volume_mode == "receptor": raise RuntimeError("Unexpected excluded volume mode.") args = [] if xvol_settings.min_surface_to_volume_distance: buff_dist = xvol_settings.min_surface_to_volume_distance args.extend(["-buff", buff_dist]) if xvol_settings.receptor_radii_size_value: args.extend(["-radius", xvol_settings.receptor_radii_size_value]) if xvol_settings.receptor_radii_size_prop: args.extend(["-rprop", xvol_settings.receptor_radii_size_prop]) if xvol_settings.receptor_radii_scaling_value: radii_scale = xvol_settings.receptor_radii_scaling_value args.extend(["-scale", radii_scale]) if xvol_settings.receptor_radii_scaling_prop: args.extend(["-sprop", xvol_settings.receptor_radii_scaling_prop]) if xvol_settings.receptor_shell_limit: args.extend(["-limit", xvol_settings.receptor_shell_limit]) if xvol_settings.append_excluded_volumes: args.append("-append") with fileutils.TempStructureFile([receptor_st]) as receptor_file: args = ["-receptor", receptor_file] + args xvol = self._runCreateXvolCommand(XVOL_RECEPTOR_DRIVER, args) return xvol
def _runCreateXvolCommand(self, xvol_driver, args): """ Build and run the excluded volume driver. All excluded volume calculations rquire a hypothesis name to work from. :param xvol_driver: excluded volume driver name :type xvol_driver: str :param args: list of command arguments :type args: list :return: a new excluded volume based on a given hypothesis :rtype: `phase.PhpExclVol` """ # Create temp hypothesis file for the backend with fileutils.tempfilename(suffix=".phypo") as temp_hypo: # Build command phase.PhpHypoAdaptor(self.base_hypo).save(temp_hypo, True) cmd = [xvol_driver, "-hypo", fileutils.splitext(temp_hypo)[0]] cmd.extend([str(a) for a in args]) # Run the utilitiy try: subprocess.check_output(cmd, universal_newlines=True) except subprocess.CalledProcessError as e: logger.error("Command:\n" + " ".join(e.cmd)) logger.error("Output:\n" + e.output) raise RuntimeError("create_xvol command has failed.") hypo = hypothesis.PhaseHypothesis(temp_hypo) return hypo.getXvol()