Source code for schrodinger.application.desmond.systype

"""
Facilities for detecting type of model systems.

Copyright Schrodinger, LLC. All rights reserved.
"""

import os

from schrodinger import structure
from schrodinger.application.desmond import cms
from schrodinger.application.desmond import constants
from schrodinger.application.desmond import struc as cst
from schrodinger.structutils import analyze


[docs]class UnknownAppError(Exception): pass
[docs]class UnknownRuleError(Exception): pass
[docs]class FormatError(Exception): pass
[docs]class DetectionError(Exception): pass
class _TypeBaseMeta(type): def __init__(cls, name, bases, dict): cls.typer_cls[cls.NAME] = cls
[docs]class TyperBase(object, metaclass=_TypeBaseMeta): typer_cls = {} NAME = "generic" RULE = {} STRING = { None: "", }
[docs] @staticmethod def prepare(*arg, **kwarg): pass
[docs] @staticmethod def check_rule(systype, rule): return True
[docs] @staticmethod def detect(struc, filename): pass
[docs] @staticmethod def has_rule(rule): return False
[docs] @staticmethod def get_trait(struc): return []
[docs]class DesmondTyper(TyperBase): NAME = "desmond" # Type codes: UNKNOWN = 0 MATURE_REGULAR = 101 MATURE_FEP = 102 MATURE_AFEP = 103 RAW_REGULAR = 201 RAW_FEP = 202 RAW_AFEP = 203 STRING = { MATURE_REGULAR: "a mature model system created for regular molecular dynamics simulations", MATURE_FEP: "a mature model system created for FEP calculations", MATURE_AFEP: "a mature model system created for absolute FEP calculations", RAW_REGULAR: "a raw geometry for regular molecular dynamics simulations", RAW_FEP: "raw geometries created for FEP calculations", RAW_AFEP: "raw geometries created for absolute FEP calculations", } RULE = { "mature_regular": [ MATURE_REGULAR, MATURE_AFEP, ], "mature_fep": [ MATURE_FEP, MATURE_AFEP, ], "mature_afep": [MATURE_AFEP,], "mature": [ MATURE_REGULAR, MATURE_FEP, MATURE_AFEP, ], "raw_regular": [ RAW_REGULAR, RAW_AFEP, ], "raw_fep": [ RAW_FEP, RAW_AFEP, ], "raw_afep": [RAW_AFEP,], "raw": [ RAW_REGULAR, RAW_FEP, RAW_AFEP, ], "regular": [ MATURE_REGULAR, MATURE_AFEP, RAW_REGULAR, RAW_AFEP, ], "fep": [ MATURE_FEP, MATURE_AFEP, RAW_FEP, RAW_AFEP, ], "afep": [ MATURE_AFEP, RAW_AFEP, ], "auto": [ MATURE_REGULAR, MATURE_FEP, MATURE_AFEP, RAW_REGULAR, RAW_FEP, RAW_AFEP, ], }
[docs] @staticmethod def detect(struc, filename): """ """ try: struc = cms.check_sanity(struc) type_ = cms.get_model_system_type(struc[1:]) type_map = { constants.SystemType.OTHER: DesmondTyper.MATURE_REGULAR, constants.SystemType.ALCHEMICAL: DesmondTyper.MATURE_FEP, constants.SystemType.BINDING: DesmondTyper.MATURE_AFEP } return type_map[type_] except ( KeyError, ValueError, ): pass # DesmondTyper.RAW_FEP? env_ct = [] ref_ct = [] mut_ct = [] for st in struc: try: if (st.property[constants.FEP_FRAGNAME] == "none"): ref_ct.append(st) else: mut_ct.append(st) except KeyError: env_ct.append(st) if (ref_ct != [] and mut_ct != []): for st in ref_ct + mut_ct: try: a = st.atom[1].property[constants.FEP_SUBST] except KeyError: return DesmondTyper.RAW_FEP if (len(ref_ct) > 1): raise TypeError( "More than 1 reference CT were defined for perturbations") return DesmondTyper.RAW_FEP elif (ref_ct == [] and mut_ct != []): raise TypeError("Reference CT not found") # DesmondTyper.RAW_AFEP? for st in struc: atom_property = list(st.atom[1].property) if (constants.FEP_ABSOLUTE_LIGAND in atom_property): if (constants.FEP_ABSOLUTE_ENERGY in atom_property): lig_atom = set( analyze.evaluate_asl( st, f"atom.{constants.FEP_ABSOLUTE_LIGAND} 1")) ene_atom = set( analyze.evaluate_asl( st, f"atom.{constants.FEP_ABSOLUTE_ENERGY} 1")) if (lig_atom != ene_atom): raise TypeError( f"Atom properties \"{constants.FEP_ABSOLUTE_ENERGY}\" and \"{constants.FEP_ABSOLUTE_LIGAND}\" does NOT match with " "each other.\n" "The system might be setup for ligand-binding FEP calculations but atom " "properties were not set correctly for that purpose." ) if (lig_atom != set()): return DesmondTyper.RAW_AFEP else: raise TypeError( f"Atom property \"{constants.FEP_ABSOLUTE_ENERGY}\" is missing while \"{constants.FEP_ABSOLUTE_LIGAND}\" is defined.\n" "The system might be setup for ligand-binding FEP calculations but atom properties " "were not set correctly for that purpose.") return DesmondTyper.RAW_REGULAR
[docs] @staticmethod def has_rule(rule): return rule in DesmondTyper.RULE
[docs] @staticmethod def check_rule(systype, rule): return systype in DesmondTyper.RULE[rule]
[docs] @staticmethod def check_system(struc, filename, rule): return DesmondTyper.check_rule(DesmondTyper.detect(struc, filename), rule)
[docs] @staticmethod def get_trait(struc): trait = [] for st in struc: try: if (st.property[constants.CT_TYPE] == constants.CT_TYPE.VAL.MEMBRANE): trait.append(constants.CT_TYPE.VAL.MEMBRANE) except KeyError: pass return trait
[docs]class McproTyper(TyperBase): NAME = "mcpro" # Type codes: UNKNOWN = 0 RAW_REGULAR = 201 RAW_FEP = 202 STRING = { RAW_REGULAR: "a raw geometry for regular monte carlo simulations", RAW_FEP: "raw geometries created for FEP calculations", } RULE = { "raw_regular": [RAW_REGULAR,], "raw_fep": [RAW_FEP,], "raw": [ RAW_FEP, RAW_REGULAR, ], "regular": [RAW_REGULAR,], "fep": [RAW_FEP,], "auto": [ RAW_FEP, RAW_REGULAR, ], }
[docs] @staticmethod def detect(struc, filename): # McproTyper.RAW_FEP? env_ct = [] ref_ct = [] mut_ct = [] for st in struc: try: if (st.property[constants.FEP_FRAGNAME] == "none"): ref_ct.append(st) else: mut_ct.append(st) except KeyError: env_ct.append(st) if (ref_ct != [] and mut_ct != []): for st in ref_ct + mut_ct: try: a = st.atom[1].property[constants.FEP_SUBST] except KeyError: raise KeyError( f"Property '{constants.FEP_SUBST}' not defined for perturbed atoms" ) if (len(ref_ct) > 1): raise TypeError( "More than 1 reference CT were defined for perturbations") return McproTyper.RAW_FEP elif (ref_ct == [] and mut_ct != []): raise TypeError("Reference CT not found") return McproTyper.RAW_REGULAR
[docs] @staticmethod def has_rule(rule): return rule in McproTyper.RULE
[docs] @staticmethod def check_rule(systype, rule): return systype in McproTyper.RULE[rule]
[docs] @staticmethod def check_system(struc, filename, rule): return McproTyper.check_rule(McproTyper.detect(struc, filename), rule)
[docs]class WatermapTyper(TyperBase): NAME = "watermap" RAW_REGULAR = 201 STRING = { RAW_REGULAR: "a raw geometry for regular watermap jobs", } RULE = { "regular": [RAW_REGULAR,], "": [RAW_REGULAR,], }
[docs] @staticmethod def detect(struc, filename): return WatermapTyper.RAW_REGULAR
[docs] @staticmethod def has_rule(rule): return rule in WatermapTyper.RULE
[docs] @staticmethod def check_rule(systype, rule): return systype in WatermapTyper.RULE[rule]
[docs] @staticmethod def check_system(struc, filename, rule): return WatermapTyper.check_rule(WatermapTyper.detect(struc, filename), rule)
[docs] @staticmethod def prepare(stage, filename): import schrodinger.utils.sea as sea struc = cst.read_all_ct(filename) solute_fname = filename + "_solute.mae" ligand_fname = filename + "_ligand.mae" recept_fname = filename + "_recept.mae" with structure.StructureWriter(solute_fname) as writer: for ct in struc: if (ct.property[constants.CT_TYPE] not in [ constants.CT_TYPE.VAL.LIGAND, constants.CT_TYPE.VAL.RECEPTOR, ]): writer.append(ct) with structure.StructureWriter(ligand_fname) as writer: for ct in struc: if (ct.property[constants.CT_TYPE] in [ constants.CT_TYPE.VAL.LIGAND, ]): writer.append(ct) with structure.StructureWriter(recept_fname) as writer: for ct in struc: if (ct.property[constants.CT_TYPE] in [ constants.CT_TYPE.VAL.RECEPTOR, ]): writer.append(ct) new_set_family = sea.Map() new_set_family["vrun"] = sea.Map( "jin_must_transfer_file = ['!append!' '%s' '%s'] " "backend.vrun.plugin.TestParticleInsertion.ligand_file = '%s'" % ( ligand_fname, "$JOBNAME-cluster.maegz", os.path.basename(ligand_fname), )) new_set_family["watermap_cluster"] = sea.Map( "ligand_file = '%s' protein_file = '%s'" % ( ligand_fname, recept_fname, )) new_set_family["watermap_post_analysis"] = sea.Map( "ligand_file = '%s' protein_file = '%s'" % ( ligand_fname, recept_fname, )) new_set_family["simulate"] = sea.Map( "jin_must_transfer_file = ['!append!' '%s'] " "backend.mdsim.plugin.SpatialActiveSite.ligand_file = '%s'" % ( ligand_fname, os.path.basename(ligand_fname), )) new_set_family["trim"] = sea.Map("erase2 = ['!append!' [0 '%s']]" % ligand_fname) stage.param.set_family.update(new_set_family)
[docs]class SysType:
[docs] def __init__(self, typer_rule=None): try: typer, rule = typer_rule.split(':') except ValueError: typer, rule = typer_rule, "" typer = typer.strip() rule = rule.strip() try: self.typer = TyperBase.typer_cls[typer] except KeyError: raise UnknownAppError("Unknown application: %s" % typer) self.rule = rule if (rule and not self.typer.has_rule(self.rule)): raise UnknownRuleError("Unknown rule: %s, for application \"%s\"" % (rule, typer))
[docs] def check_system(self, filename): struc = cst.read_all_ct(filename) try: systype = self.typer.detect(struc, filename) except Exception as e: raise DetectionError("Detecting failed: %s" % str(e)) return (self.typer.check_rule(systype, self.rule), systype, self.typer.STRING[systype])
[docs] def get_trait(self, filename): struc = cst.read_all_ct(filename) return self.typer.get_trait(struc)
[docs] def prepare(self, *arg, **kwarg): self.typer.prepare(*arg, **kwarg)