Source code for schrodinger.application.desmond.stage.app.fragment_linking.utils

import os
import typing

from schrodinger.application.desmond import measurement
from schrodinger.application.desmond import struc
from schrodinger.application.desmond.constants import FEP_DG_PREFIX
from schrodinger.application.desmond.constants import FEP_RESTRAINT_CORRECTION
from schrodinger.application.desmond.constants import FEP_TRANSFER_FREE_ENERGY
from schrodinger.application.desmond.constants import FRAGMENT_LINKING_JOBS
from schrodinger.application.desmond.constants import FRAGMENT_LINKING_SIGN
from schrodinger.application.desmond.constants import CorrectionTerm

if typing.TYPE_CHECKING:
    from schrodinger.application.scisol.packages.fep import graph


[docs]class MissingValueError(Exception): pass
[docs]def collect_dg_values(g: "graph.Graph", launch_dir: str, jobname: str): """ For each fragment linking edge, collect the dg values from the `*out.mae` files and update the edge properties. :param g: Graph to update in place. :param launch_dir: Path containing the FepLauncher job outputs. :param jobname: Name of the main job. :raises MissingValueError: If one or more edges were missing values. """ err = '' for e in g.edges_iter(): if not e.is_fragment_linking: continue e.complex_dg = None e.solvent_dg = None e.fragment_dgs = [] from_id = e.short_id[0] to_id = e.short_id[1] from_title = e[0].struc.title to_title = e[1].struc.title job_to_dG = {} restr_correction = None sign = None for fragment_linking_job in FRAGMENT_LINKING_JOBS.VAL: outpath = f'{launch_dir}/{jobname}_{from_id}_{to_id}_{fragment_linking_job}-out.mae' if not os.path.exists(outpath): continue cts = struc.read_all_ct(outpath) for ct in cts: if ct.property.get(FEP_DG_PREFIX): dG = measurement.Measurement.from_string( ct.property[FEP_DG_PREFIX]) job_to_dG[fragment_linking_job] = dG elif ct.property.get(FEP_TRANSFER_FREE_ENERGY): dG = measurement.Measurement.from_string( ct.property[FEP_TRANSFER_FREE_ENERGY]) job_to_dG[fragment_linking_job] = dG if ct.property.get(FEP_RESTRAINT_CORRECTION): restr_correction = measurement.Measurement( ct.property[FEP_RESTRAINT_CORRECTION], 0.0) if ct.property.get(FRAGMENT_LINKING_SIGN): sign = ct.property[FRAGMENT_LINKING_SIGN] # Check for missing properties missing_jobs = set(FRAGMENT_LINKING_JOBS.VAL) - set(job_to_dG.keys()) if len(missing_jobs): err += f"Could not find fragment linking job(s) for '{from_title}' '{to_title}': {missing_jobs}.\n" continue if restr_correction is None: err += f"Could not find fragment linking restraint correction for '{from_title}' '{to_title}'.\n" continue if sign is None: err += f"Could not find fragment linking sign term for '{from_title}' '{to_title}'.\n" continue # Assign the results print(f'Fragment linking for {e[0].struc.title} {e[1].struc.title}:\n') e.complex_dg = job_to_dG[FRAGMENT_LINKING_JOBS.VAL.COMPLEX] e.solvent_dg = job_to_dG[FRAGMENT_LINKING_JOBS.VAL.SOLVENT] ddg_solvation = job_to_dG[FRAGMENT_LINKING_JOBS.VAL.FRAGMENT_HYDRATION] ddg_solvation -= job_to_dG[ FRAGMENT_LINKING_JOBS.VAL.RESTRAINED_FRAGMENT_HYDRATION] ddg_solvation += restr_correction e.update_ddg_corrections_map( {CorrectionTerm.FRAGMENT_SOLVATION: ddg_solvation * sign}) print(f'complex: {job_to_dG[FRAGMENT_LINKING_JOBS.VAL.COMPLEX]}') print(f'solvent: {job_to_dG[FRAGMENT_LINKING_JOBS.VAL.SOLVENT]}') print( f'fragment hydration free energy: {job_to_dG[FRAGMENT_LINKING_JOBS.VAL.FRAGMENT_HYDRATION]}' ) print( f'restrained fragment hydration free energy: {job_to_dG[FRAGMENT_LINKING_JOBS.VAL.RESTRAINED_FRAGMENT_HYDRATION]}' ) print(f'restraint correction: {restr_correction}') print(f'ddG: {e.bennett_ddg}') if err: raise MissingValueError(err)