Source code for schrodinger.application.steps.ligprep

import os

from schrodinger.infra import mmerr
from schrodinger.models import parameters
from schrodinger import stepper
from schrodinger.utils import license
from schrodinger.utils import log

from . import dataclasses
from . import utils

# for unit test environment
try:
    from schrodinger.application.macromodel.packages.ligprep3.ligprepworkflow import \
        LigPrepWorkflow
except ImportError:
    LigPrepWorkflow = None

LIGPREP_MMERR_LEVEL = mmerr.MMERR_OFF
LIGPREP_LOG_LEVEL = log.CRITICAL

# We can only instantiate a single LigPrepWorkflow instances b/c we are not
# allowed to instantiate Epik more than once.
mm_lig_prep_workflow = None
mm_lig_prep_workflow_args = None


[docs]class LigPrepStep(stepper.MapStep): """ A step that implements the basic lig prep functionality of `Structure` objects. The settings is the list of command line arguments that are usually passed to the ligprep script, excluding the input and output arguments. Within one process more than one LigPrepStep is allowed to be created only if the settings are the same, to avoid problems if both use '-epik'. There are issues with generating tautomers even if the first generator is closed (LIGPREP-1941). """
[docs] def getLicenseRequirements(self): return {license.LIGPREP_MAIN: 1}
[docs] class Settings(parameters.CompoundParam): arg_string: str = '-bff 16 -epik -s 32' ligprep_filter_file: stepper.StepperFile = None
[docs] def validateSettings(self): return utils.validate_file( self, 'ligprep_filter_file') # optional StepperFile
def _makeLigPrepWorkflowArgs(self): """ :return: the arguments for the LigPrepWorkflow initialization :rtype: List[str] :raises AutoDesignerError: if the ligprep_filter file was defined but not found. """ # the initializer needs to have input and output files, but for my # use case they are not used. args = self.settings.arg_string.split() + ['-isd', 'foo', '-osd', 'bar'] flt_file = self.settings.ligprep_filter_file if flt_file: if not os.path.exists(flt_file): msg = (f'{self._step_id}: ligprep_filter_file "{flt_file}" not' f' found.') raise utils.StepsError(msg) args += ['-f', flt_file] return args def _getLigPrepWorkflow(self): global mm_lig_prep_workflow, mm_lig_prep_workflow_args args = self._makeLigPrepWorkflowArgs() if mm_lig_prep_workflow is None: lpwf_logger = log.get_output_logger("LigandPrepper") lpwf_logger.setLevel(LIGPREP_LOG_LEVEL) mm_lig_prep_workflow_args = args mm_lig_prep_workflow = LigPrepWorkflow(lpwf_logger, args) elif args != mm_lig_prep_workflow_args: msg = (f'{self._step_id}: a LigandPrepper with different arguments' f' was already instantiated.') raise utils.StepsError(msg) return mm_lig_prep_workflow
[docs] def mapFunction(self, struc): lpwf = self._getLigPrepWorkflow() with mmerr.Level(LIGPREP_MMERR_LEVEL): outcomes, _, _ = lpwf.run(struc) yield from outcomes
[docs] def cleanUp(self): global mm_lig_prep_workflow, mm_lig_prep_workflow_args super().cleanUp() if mm_lig_prep_workflow: mm_lig_prep_workflow.close() mm_lig_prep_workflow = None mm_lig_prep_workflow_args = None
[docs]class LigandPrepper(dataclasses.MolMolMixin, LigPrepStep): """ See also `LigPrepMixin` """
[docs] def mapFunction(self, mol): st = utils.mol_to_structure(mol, self) if st is not None: for ligprepped_st in super().mapFunction(st): mol = utils.structure_to_mol(ligprepped_st, self, mol) if mol is not None: yield mol
[docs]class MaeLigandPrepper(dataclasses.MaeMaeMixin, LigPrepStep): """ See also `LigPrepStep` """ # the parent basically implements the `Structure` input/output pass