Source code for schrodinger.application.phase.input

"""
Module for reading and writing Phase configuration/input files.
"""

import enum
import os
from collections import namedtuple

import yaml

from schrodinger.application.inputconfig import InputConfig

# Keyword specs in yaml format
YAML_DIR = "input_keywords"
YAML_COMMON = "hypothesis_find_common.yaml"  # Common pharmacophore perception
YAML_TOL = "hypothesis_tolerance.yaml"  # To add feature tolerances
YAML_XVOL = "hypothesis_xvol.yaml"  # To add excluded volumes to hypothesis


[docs]@enum.unique class InputSpecs(enum.Enum): """ Enumeration of valide PhaseHypothesisInputConfig specs. """ find_common, create_hypo, create_xvol = list(range(3))
# Mapping of InputConfig mode to corresponding keyword yaml files KEYWORD_YAML_FILE = { InputSpecs.find_common: (YAML_COMMON, YAML_TOL, YAML_XVOL), InputSpecs.create_hypo: (YAML_TOL, YAML_XVOL), InputSpecs.create_xvol: (YAML_XVOL,), } def _get_keyword_yaml_files(input_mode): """ Returns list of file paths to yaml keyword files corresponding to a given PhaseHypothesisInputConfig mode. :param input_mode: phase_hypothesis driver run mode :type input_mode: int :return: list of paths to corresponding keyword yaml files :rtype: list of str """ if not input_mode: return [] keyword_dir = os.path.join(os.path.dirname(__file__), YAML_DIR) return [os.path.join(keyword_dir, f) for f in KEYWORD_YAML_FILE[input_mode]]
[docs]class PhaseHypothesisInputConfig(InputConfig): """ Settings/Validation InputConfig class for the Phase Hypothesis Driver. The class acts as a container and validator for calling driver property setters through the (keyword, value) interface, or in the case of indexable attributes, the (keyword, index, value). """
[docs] def __init__(self, input_file=None, specs=InputSpecs.find_common): """ Initializes the inputconfig settings with given input file. :param infile: input filename :type infile: str :param specs: input yaml specs :type specs: `InputSpecs` """ # Default to the common pharmacophore specs for phase_hypothesis input_specs = self.generateSpecs(specs) InputConfig.__init__(self, infile=input_file, specs=input_specs)
[docs] def generateSpecs(self, input_mode, append_comments=False): """ Builds InputConfig spec list from yaml file stored in module directory. Optionally adds comments for keyword usage output. :param input_mode: input keyword mode :type input_mode: `InputSpecs` :param append_comments: whether to append comments to spec strings :type append_comments: bool :return: list of InputConfig spec strings :rtype: list of strings """ input_config_specs = [] for filename in _get_keyword_yaml_files(input_mode): with open(filename, 'rb') as fh: docs = yaml.load_all(fh, Loader=yaml.SafeLoader) for spec in docs: spec_string = self._getSpecString(spec) if append_comments: spec_string = (spec_string, spec['comment']) input_config_specs.append(spec_string) return input_config_specs
def _getSpecString(self, spec): """ Returns a spec string compatible with InputConfig. :param spec: dictionary of spec parameters :type spec: dict :return: InputConfig spec string, formed as keyword = value(options) :rtype: str """ params = [] if 'values' in spec: params.append('%s' % spec['values']) if 'default' in spec: params.append('default=%s' % spec['default']) if 'min' in spec: params.append('min=%s' % spec['min']) if 'max' in spec: params.append('max=%s' % spec['max']) keyword = spec['keyword'] type_str = spec['type'] param_str = ', '.join(params) spec_string = '%-33s = %s(%s)' % (keyword, type_str, param_str) return spec_string
[docs] def asNamedTuple(self): """ Returns the current settings as a validated namedtuple for driver use. :return: cast of current (validated) settings as a namedtuple :rtype: namedtuple """ self.validateValues() # Loads default settings attribute_dict = {} for keyword, value in self.iteritems(): attribute_dict[keyword.lower()] = value DriverSettings = namedtuple('DriverSettings', list(attribute_dict)) return DriverSettings(**attribute_dict)
[docs] def validateKeywords(self): """ Validates that all set keywords are supported. :raises ValueError: Error message if keyword is not supported """ for keyword in self.keys(): if keyword not in self._key_order: raise ValueError("Unsupported keyword: %s" % keyword)
[docs] def validateInput(self): """ Validates all values and keywords, removing entries that are set to None prior to inputConfig.validateValues() so it does not throw error :raises ValueError: Error message if keyword is not supported """ for keyword, value in self.items(): if value == "None": del self[keyword] self.validateValues() self.validateKeywords() # TODO: Remove with deprecated keywords if self.get("LIGAND_PERCEPTION", None): del self["USE_STEREO"] del self["USE_TITLES"]
[docs]def inputconfig_subset(specs, settings_namedtuple): """ Generates a PhaseHypothesisInputConfig using the specified specs, and corresponding values found in the namedtuple. :param specs: input yaml specs :type specs: `InputSpecs` :param settings_namedtuple: named tuple settings :type settings_namedtuple: `DriverSettings` :return: Phase InputConfig object :rtype: `PhaseHypothesisInputConfig` """ config = PhaseHypothesisInputConfig(specs=specs) for key, value in settings_namedtuple._asdict().items(): keyword = key.upper() # Convert back to InputConfig keywords if keyword in config.configspec: config[keyword] = value return config