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)
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