Source code for pestifer.tasks.ringcheck
# Author: Cameron F. Abrams, <cfa22@drexel.edu>
"""
Definition of the :class:`RingCheckTask` class for checking for pierced rings in a molecular structure.
This class is a descendant of the :class:`BaseTask <pestifer.core.basetask.BaseTask>` class and is used to check for pierced rings in a molecular structure.
It identifies configurations where a ring is pierced by another segment and can optionally delete the pierced segments.
Usage is described in the :ref:`config_ref tasks ring_check` documentation.
"""
import logging
from pathlib import Path
from .basetask import BaseTask
from ..scripters import PsfgenScripter
from ..core.artifacts import *
from ..core.errors import PestiferBuildError
from ..psfutil.psfring import ring_check
logger=logging.getLogger(__name__)
[docs]
class RingCheckTask(BaseTask):
"""
A class for checking for pierced rings
"""
_yaml_header = 'ring_check'
"""
YAML header for RingCheckTask objects.
This header is used to declare RingCheckTask objects in YAML task lists.
"""
[docs]
def do(self):
state: StateArtifacts = self.get_current_artifact('state')
cutoff: float = self.specs.get('cutoff', 3.5)
segtypes: list = self.specs.get('segtypes', ['lipid', 'glycan'])
delete_these: str = self.specs.get('delete', 'piercee')
xsc_name = state.xsc.name if state.xsc else None
if xsc_name is None:
logger.debug('No XSC in pipeline state — ring_check will run in non-periodic (vacuum) mode')
npiercings = ring_check(state.psf.name, state.pdb.name, xsc_name, cutoff=cutoff, segtypes=segtypes)
if npiercings:
ess = 's' if len(npiercings) > 1 else ''
glycan_piercings = [p for p in npiercings if p['piercee']['segtype'] == 'glycan']
other_piercings = [p for p in npiercings if p['piercee']['segtype'] != 'glycan']
if glycan_piercings:
gess = 's' if len(glycan_piercings) > 1 else ''
logger.error(f'{len(glycan_piercings)} glycan ring piercing{gess} detected — glycan residues cannot be deleted to resolve:')
for p in glycan_piercings:
logger.error(f' {p["piercee"]["segname"]}-{p["piercee"]["resid"]} pierced by {p["piercer"]["segname"]}-{p["piercer"]["resid"]}')
raise PestiferBuildError(
f'{len(glycan_piercings)} glycan ring piercing{gess} detected; '
f'rebuild the system to resolve (e.g. use a different random seed or add more minimization before ring_check)'
)
if delete_these == "none":
for r in other_piercings:
logger.error(f' Piercing of {r["piercee"]["segname"]}-{r["piercee"]["resid"]} by {r["piercer"]["segname"]}-{r["piercer"]["resid"]}')
raise PestiferBuildError(
f'{len(other_piercings)} pierced-ring configuration{ess} found; '
f'ring_check is configured with delete=none — resolve these manually or change the delete setting'
)
elif other_piercings:
self.next_basename('ring_check')
pg: PsfgenScripter = self.get_scripter('psfgen')
pg.newscript(self.basename)
pg.load_project(state.psf.name, state.pdb.name)
oess = 's' if len(other_piercings) > 1 else ''
logger.debug(f'Deleting all {delete_these}s from {len(other_piercings)} pierced-ring configuration{oess}')
for r in other_piercings:
logger.debug(f' Deleting segname {r[delete_these]["segname"]} residue {r[delete_these]["resid"]}')
pg.addline(f'delatom {r[delete_these]["segname"]} {r[delete_these]["resid"]}')
pg.writescript(self.basename)
pg.runscript()
self.register(dict(psf=PSFFileArtifact(self.basename), pdb=PDBFileArtifact(self.basename), xsc=state.xsc), key='state', artifact_type=StateArtifacts)
self.register(self.basename, key='tcl', artifact_type=PsfgenInputScriptArtifact)
self.register(self.basename, key='log', artifact_type=PsfgenLogFileArtifact)
self.result = 0
return self.result