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