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 input as phase_input
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()