diff --git a/devtools/conda-envs/macos-latest/spectrum.yaml b/devtools/conda-envs/macos-latest/spectrum.yaml index fccd9415..5361d1c1 100644 --- a/devtools/conda-envs/macos-latest/spectrum.yaml +++ b/devtools/conda-envs/macos-latest/spectrum.yaml @@ -32,9 +32,6 @@ dependencies: - biopython - mdanalysis - openeye-toolkits - - openfe ~=1.0 - - openmm - - gufe >=1.0.0 - pymol-open-source - rdkit - plip diff --git a/drugforge-alchemy/pyproject.toml b/drugforge-alchemy/pyproject.toml index ec179e8c..f4a34e1e 100644 --- a/drugforge-alchemy/pyproject.toml +++ b/drugforge-alchemy/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [] "Bug Tracker" = "https://github.com/choderalab/drugforge/issues" [project.scripts] -asap-alchemy = "drugforge.alchemy.cli.cli:alchemy" +drugforge-alchemy = "drugforge.alchemy.cli.cli:alchemy" [tool.setuptools.packages.find] where = ["."] diff --git a/drugforge-cli/pyproject.toml b/drugforge-cli/pyproject.toml index 9130b6c6..ef8f54e7 100644 --- a/drugforge-cli/pyproject.toml +++ b/drugforge-cli/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [] "Bug Tracker" = "https://github.com/choderalab/drugforge/issues" [project.scripts] -asap-cli = "drugforge.cli.cli:cli" +drugforge-cli = "drugforge.cli.cli:cli" [tool.setuptools.packages.find] where = ["."] diff --git a/drugforge-data/drugforge/data/schema/ligand.py b/drugforge-data/drugforge/data/schema/ligand.py index 4114ef97..05c7e28c 100644 --- a/drugforge-data/drugforge/data/schema/ligand.py +++ b/drugforge-data/drugforge/data/schema/ligand.py @@ -47,7 +47,7 @@ ) if TYPE_CHECKING: - import openfe + import gufe from rdkit import Chem logger = logging.getLogger(__name__) @@ -386,16 +386,16 @@ def to_rdkit(self) -> "Chem.Mol": set_SD_data(rdkit_mol, data) return rdkit_mol - def to_openfe(self) -> "openfe.SmallMoleculeComponent": + def to_openfe(self) -> "gufe.components.SmallMoleculeComponent": """ Convert to an openfe SmallMoleculeComponent via the rdkit interface. """ - import openfe + import gufe - return openfe.SmallMoleculeComponent.from_rdkit(self.to_rdkit()) + return gufe.components.SmallMoleculeComponent.from_rdkit(self.to_rdkit()) @classmethod - def from_openfe(cls, mol: "openfe.SmallMoleculeComponent", **kwargs) -> "Ligand": + def from_openfe(cls, mol: "gufe.components.SmallMoleculeComponent", **kwargs) -> "Ligand": """ Create a Ligand from an openfe SmallMoleculeComponent """ diff --git a/drugforge-data/drugforge/data/testing/test_files.yaml b/drugforge-data/drugforge/data/testing/test_files.yaml index c8aa00bd..65d8e596 100644 --- a/drugforge-data/drugforge/data/testing/test_files.yaml +++ b/drugforge-data/drugforge/data/testing/test_files.yaml @@ -351,7 +351,7 @@ files: - resource: Mpro-YP_009725301_AFold_processed.pdb sha256hash: 3cdc93de0186243d790e7abd61d77eacde649f547f3d0cd0aaa58243631431f8 - # asap-spectrum testing + # spectrum testing - resource: SARS_blast_results.xml sha256hash: d6e59d1f6b2eeee5162cca4dbeee7ffcd56eeeabdb733a505ff86ee1588cf8f6 diff --git a/drugforge-ml/pyproject.toml b/drugforge-ml/pyproject.toml index a0e56e64..c3eb153d 100644 --- a/drugforge-ml/pyproject.toml +++ b/drugforge-ml/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [] "Bug Tracker" = "https://github.com/choderalab/drugforge/issues" [project.scripts] -asap-ml = "drugforge.ml.cli:ml" +drugforge-ml = "drugforge.ml.cli:ml" convert-ds = "drugforge.ml.scripts.convert_dataset:convert" [tool.setuptools.packages.find] diff --git a/drugforge-simulation/drugforge/simulation/cli.py b/drugforge-simulation/drugforge/simulation/cli.py index fcb856bd..341928d5 100644 --- a/drugforge-simulation/drugforge/simulation/cli.py +++ b/drugforge-simulation/drugforge/simulation/cli.py @@ -13,12 +13,14 @@ output_dir, pdb_file, use_dask, + target ) from drugforge.data.readers.molfile import MolFileFactory from drugforge.data.schema.complex import Complex from drugforge.data.util.dask_utils import DaskType, make_dask_client_meta from drugforge.data.util.logging import FileLogger from drugforge.simulation.simulate import OpenMMPlatform, VanillaMDSimulator +from drugforge.simulation.simulate import minimize_from_pdb from openmm import unit @@ -144,3 +146,43 @@ def vanilla_md( @pdb_file def szybki(): raise NotImplementedError("Szybki simulation not yet implemented") + +@simulation.command() +@pdb_file +@click.option( + "--min-out", + type=str, + default="minimized.pdb", + help="Optional file name for saving result of BLAST search", +) +@output_dir +@md_openmm_platform +@target +@loglevel +def minimize( + pdb_file: Union[Path, str], + min_out: Union[Path, str], + output_dir: Union[Path, str], + md_openmm_platform: str, + target: str, + loglevel: Union[int, str] = logging.INFO, +): + logger = FileLogger( + "", # default root logger so that dask logging is forwarded + path=output_dir, + logfile="vanilla_md.log", + stdout=True, + level=loglevel, + ).getLogger() + + logger.info("Running minimization") + + minimize_from_pdb( + pdb_file=pdb_file, + min_out=min_out, + output_dir=output_dir, + md_openmm_platform=md_openmm_platform, + target=target, + ) + logger.info(f"Minimized structure saved to {min_out}") + \ No newline at end of file diff --git a/drugforge-simulation/drugforge/simulation/simulate.py b/drugforge-simulation/drugforge/simulation/simulate.py index 5d4712d1..0f543674 100644 --- a/drugforge-simulation/drugforge/simulation/simulate.py +++ b/drugforge-simulation/drugforge/simulation/simulate.py @@ -1,5 +1,6 @@ import abc import logging +import os import shutil import warnings from pathlib import Path @@ -653,3 +654,72 @@ def run_production_simulation( def provenance(self) -> dict[str, str]: return {} + +def minimize_from_pdb( + pdb_file: Union[Path, str], + min_out: Union[Path, str], + output_dir: Union[Path, str], + md_openmm_platform: str, + target: str, +) -> Union[Path, str]: + """MD energy minimization a protein ligand complex. + Energy minimization is performed with OpenMM (no equilibration or production MD is performed). + + Parameters + ---------- + pdb_complex : Union[Path, str] + Path to protein ligand complex pdb + min_out : Union[Path, str] + Output file with minimized pdb + out_dir : Union[Path, str] + Directory to save output minimized complex + md_platform : str + MD OpenMM platform [CPU, CUDA, OpenCL, Reference, Fastest] + target : str + Name of reference target (see drugforge documentation). + + Returns + ------- + str + Path to minimized file + """ + from drugforge.data.schema.complex import Complex + from drugforge.modeling.schema import PreppedComplex + + if Path(min_out).is_file(): + logger.warning( + f"The file {min_out} already exists. The minimization will be skipped" + ) + return min_out + comp_name = "MOL" + cmp = Complex.from_pdb( + pdb_file, + ligand_kwargs={"compound_name": comp_name}, + target_kwargs={"target_name": target}, + ) + out_dir = Path(output_dir) + prepped_cmp = PreppedComplex.from_complex(cmp) + prepped_cmp.target.to_pdb_file(out_dir / "target.pdb") + cmp.ligand.to_sdf(out_dir / "ligand.sdf") + + md_simulator = VanillaMDSimulator( + output_dir=out_dir, + openmm_platform=md_openmm_platform, + minimize_only=True, + num_steps=1, + ) + simulation_results = md_simulator.simulate( + [(out_dir / "target.pdb", out_dir / "ligand.sdf")], + outpaths=[out_dir], + failure_mode="skip", + ) + min_path = simulation_results[0].minimized_pdb_path + shutil.move(min_path, min_out) + shutil.rmtree(f"{out_dir}/target_ligand", ignore_errors=True) + for file_path in [f"{out_dir}/target.pdb", f"{out_dir}/ligand.sdf"]: + try: + os.remove(file_path) + except FileNotFoundError: + pass + + return min_out \ No newline at end of file diff --git a/drugforge-simulation/drugforge/simulation/tests/conftest.py b/drugforge-simulation/drugforge/simulation/tests/conftest.py index 3b25f2a0..2b7fa48f 100644 --- a/drugforge-simulation/drugforge/simulation/tests/conftest.py +++ b/drugforge-simulation/drugforge/simulation/tests/conftest.py @@ -12,7 +12,7 @@ def ligand_path(): @pytest.fixture(scope="session") def protein_path(): - return fetch_test_file("Mpro-x0071_0A_ERI-UCB-8c6b7d0d-1.pdb") + return fetch_test_file("Mpro-P2660_0A_bound.pdb") @pytest.fixture(scope="session") diff --git a/drugforge-simulation/drugforge/simulation/tests/test_simulate.py b/drugforge-simulation/drugforge/simulation/tests/test_simulate.py index d70ef5f0..923c07c2 100644 --- a/drugforge-simulation/drugforge/simulation/tests/test_simulate.py +++ b/drugforge-simulation/drugforge/simulation/tests/test_simulate.py @@ -3,6 +3,7 @@ from unittest import mock import pytest +from pathlib import Path from drugforge.docking.docking import DockingResult from drugforge.docking.openeye import POSITDockingResults from drugforge.simulation.cli import simulation as cli @@ -201,3 +202,27 @@ def _simulate_patch( ] result = runner.invoke(cli, args) assert click_success(result) + + + +@pytest.mark.skipif(os.getenv("SKIP_EXPENSIVE_TESTS"), reason="Expensive tests skipped") +def test_minimize_cli(protein_path, tmp_path): + """Test minimization of protein PDB using OpenMM.""" + runner = CliRunner() + min_out = f"{tmp_path}/min_out.pdb" + args = [ + "minimize", + "--pdb-file", + protein_path, + "--min-out", + min_out, + "--output-dir", + tmp_path, + "--md-openmm-platform", + "CPU", + "--target", + "SARS-CoV-2-Mpro", + ] + result = runner.invoke(cli, args) + assert click_success(result) + assert Path(min_out).exists() \ No newline at end of file diff --git a/drugforge-spectrum/drugforge/spectrum/score.py b/drugforge-spectrum/drugforge/spectrum/score.py index e4bee1a5..9d079bf5 100644 --- a/drugforge-spectrum/drugforge/spectrum/score.py +++ b/drugforge-spectrum/drugforge/spectrum/score.py @@ -12,7 +12,6 @@ ) from drugforge.data.backend.openeye import oechem, split_openeye_mol from drugforge.spectrum.calculate_rmsd import rmsd_alignment -from drugforge.simulation.simulate import VanillaMDSimulator from drugforge.data.services.postera.manifold_data_validation import TargetTags from drugforge.data.metadata.resources import active_site_chains @@ -641,73 +640,3 @@ def score_gnina(pdb_target:str, ] ) return df - - -def minimize_structure( - pdb_complex: Union[Path, str], - min_out: Union[Path, str], - out_dir: Union[Path, str], - md_platform: str, - comp_name: str, - target_name: str, -) -> Union[Path, str]: - """MD energy minimization a protein ligand complex. - Energy minimization is performed with OpenMM (no equilibration or production MD is performed). - - Parameters - ---------- - pdb_complex : Union[Path, str] - Path to protein ligand complex pdb - min_out : Union[Path, str] - Output file with minimized pdb - out_dir : Union[Path, str] - Directory to save output minimized complex - md_platform : str - MD OpenMM platform [CPU, CUDA, OpenCL, Reference, Fastest] - comp_name : str - Name of to give to complex. Can be arbitrary. - target_name : str - Name of reference target (see drugforge documentation). - - Returns - ------- - str - Path to minimized file - """ - - if Path(min_out).is_file(): - logger.warning( - f"The file {min_out} already exists. The minimization will be skipped" - ) - return min_out - cmp = Complex.from_pdb( - pdb_complex, - ligand_kwargs={"compound_name": comp_name}, - target_kwargs={"target_name": target_name}, - ) - out_dir = Path(out_dir) - prepped_cmp = PreppedComplex.from_complex(cmp) - prepped_cmp.target.to_pdb_file(out_dir / "target.pdb") - cmp.ligand.to_sdf(out_dir / "ligand.sdf") - - md_simulator = VanillaMDSimulator( - output_dir=out_dir, - openmm_platform=md_platform, - minimize_only=True, - num_steps=1, - ) - simulation_results = md_simulator.simulate( - [(out_dir / "target.pdb", out_dir / "ligand.sdf")], - outpaths=[out_dir], - failure_mode="skip", - ) - min_path = simulation_results[0].minimized_pdb_path - shutil.move(min_path, min_out) - shutil.rmtree(f"{out_dir}/target_ligand", ignore_errors=True) - for file_path in [f"{out_dir}/target.pdb", f"{out_dir}/ligand.sdf"]: - try: - os.remove(file_path) - except FileNotFoundError: - pass - - return min_out diff --git a/drugforge-spectrum/drugforge/spectrum/tests/test_score.py b/drugforge-spectrum/drugforge/spectrum/tests/test_score.py index 56e2b48c..f2fa272d 100644 --- a/drugforge-spectrum/drugforge/spectrum/tests/test_score.py +++ b/drugforge-spectrum/drugforge/spectrum/tests/test_score.py @@ -7,7 +7,6 @@ dock_and_score, get_ligand_rmsd, score_autodock_vina, - minimize_structure ) from drugforge.spectrum.calculate_rmsd import get_binding_site_rmsd from drugforge.docking.scorer import ChemGauss4Scorer @@ -105,18 +104,3 @@ def test_vina_score(target_prepped_vina, ligand_prepped_vina): dock=False, ) assert df_vina["Vina-score-premin"].values[0] < 0 - - -@pytest.mark.skipif(os.getenv("SKIP_EXPENSIVE_TESTS"), reason="Expensive tests skipped") -def test_minimize(protein_path, tmp_path): - """Test minimization of protein PDB using OpenMM.""" - min_out = f"{tmp_path}/min_out.pdb" - minimize_structure( - pdb_complex = protein_path, - min_out = min_out, - out_dir = tmp_path, - md_platform = 'CPU', - comp_name = 'Mol', - target_name = 'SARS-CoV-2',) - - assert Path(min_out).exists() \ No newline at end of file diff --git a/drugforge-workflows/drugforge/workflows/spectrum_workflows/cli.py b/drugforge-workflows/drugforge/workflows/spectrum_workflows/cli.py index 2cd8d2b0..89bba4a9 100644 --- a/drugforge-workflows/drugforge/workflows/spectrum_workflows/cli.py +++ b/drugforge-workflows/drugforge/workflows/spectrum_workflows/cli.py @@ -564,7 +564,7 @@ def fitness_alignment( "--ml-score", is_flag=True, default=False, - help="Whether to employ asap-implemented ML models to score poses.", + help="Whether to employ implemented ML models to score poses.", ) @click.option( "--bsite-rmsd", diff --git a/drugforge-workflows/drugforge/workflows/spectrum_workflows/score_complex.py b/drugforge-workflows/drugforge/workflows/spectrum_workflows/score_complex.py index 9abd5595..051607e2 100644 --- a/drugforge-workflows/drugforge/workflows/spectrum_workflows/score_complex.py +++ b/drugforge-workflows/drugforge/workflows/spectrum_workflows/score_complex.py @@ -1,13 +1,12 @@ from drugforge.data.schema.complex import Complex from drugforge.data.util.logging import FileLogger -from drugforge.simulation.simulate import OpenMMPlatform +from drugforge.simulation.simulate import minimize_from_pdb, OpenMMPlatform from drugforge.docking.scorer import ChemGauss4Scorer from drugforge.spectrum.score import ( ScoreSpectrumInputsBase, dock_and_score, get_ligand_rmsd, score_autodock_vina, - minimize_structure, score_gnina, ) from drugforge.spectrum.calculate_rmsd import get_binding_site_rmsd @@ -26,7 +25,7 @@ class ScoreInputs(ScoreSpectrumInputsBase): Parameters ---------- docking_csv : Path - Path to docking output csv file, from previoud asap-docking step. + Path to docking output csv file, from previous drugforge-docking step. ligand_regex : str Pattern for extracting ligand ID from file string. protein_regex : str @@ -34,7 +33,7 @@ class ScoreInputs(ScoreSpectrumInputsBase): bsite_rmsd : bool Whether to calculate binding site RMSD. ml_score : bool - Whether to employ asap-ml models to score poses. + Whether to employ ml models to score poses. minimize : bool Whether to minimize the pdb structures before running scoring. md_openmm_platform : OpenMMPlatform @@ -74,7 +73,7 @@ class ScoreInputs(ScoreSpectrumInputsBase): ) ml_score: bool = Field( - False, description="Whether to employ asap-implemented ML models to score poses." + False, description="Whether to employ implemented ML models to score poses." ) minimize: bool = Field( @@ -248,7 +247,7 @@ def score_complex_workflow(inputs: ScoreInputs): try: min_out = f"{min_folder}/{tag}_min.pdb" logger.info("Running MD minimization of %s", tag) - minimize_structure( + minimize_from_pdb( file_min, min_out, min_folder, diff --git a/drugforge-workflows/pyproject.toml b/drugforge-workflows/pyproject.toml index 29c72f9f..cc6ade8e 100644 --- a/drugforge-workflows/pyproject.toml +++ b/drugforge-workflows/pyproject.toml @@ -26,9 +26,9 @@ dependencies = [] "Bug Tracker" = "https://github.com/choderalab/drugforge/issues" [project.scripts] -asap-docking = "drugforge.workflows.docking_workflows.cli:docking" -asap-prep = "drugforge.workflows.prep_workflows.cli:protein_prep" -asap-spectrum = "drugforge.workflows.spectrum_workflows.cli:spectrum" +drugforge-docking = "drugforge.workflows.docking_workflows.cli:docking" +drugforge-prep = "drugforge.workflows.prep_workflows.cli:protein_prep" +drugforge-spectrum = "drugforge.workflows.spectrum_workflows.cli:spectrum" [tool.setuptools.packages.find] where = ["."]