├── .gitignore ├── ChangeLog.md ├── DockStream.jpg ├── LICENSE ├── README.md ├── __init__.py ├── analysis.py ├── benchmarking.py ├── docker.py ├── dockstream ├── __init__.py ├── analysis.py ├── config │ ├── logging │ │ ├── debug.json │ │ ├── default.json │ │ └── verbose.json │ ├── rDock │ │ └── standard_reference_ligand.prm │ └── tests_config │ │ └── example.config.json ├── containers │ ├── __init__.py │ ├── analysis_container.py │ ├── container.py │ ├── docking_container.py │ └── target_preparation_container.py ├── core │ ├── AutodockVina │ │ ├── AutodockVina_docker.py │ │ ├── AutodockVina_result_parser.py │ │ ├── AutodockVina_target_preparator.py │ │ └── __init__.py │ ├── Corina │ │ ├── Corina_ligand_preparator.py │ │ └── __init__.py │ ├── Gold │ │ ├── Gold_docker.py │ │ ├── Gold_result_parser.py │ │ ├── Gold_target_preparator.py │ │ └── __init__.py │ ├── OpenEye │ │ ├── OpenEye_docker.py │ │ ├── OpenEye_ligand_preparator.py │ │ ├── OpenEye_result_parser.py │ │ ├── OpenEye_target_preparator.py │ │ ├── OpenEye_transformator.py │ │ └── __init__.py │ ├── OpenEyeHybrid │ │ ├── Omega_ligand_preparator.py │ │ ├── OpenEyeHybrid_docker.py │ │ └── OpenEyeHybrid_result_parser.py │ ├── RDkit │ │ ├── RDkit_ligand_preparator.py │ │ ├── RDkit_stereo_enumerator.py │ │ └── __init__.py │ ├── Schrodinger │ │ ├── Glide_docker.py │ │ ├── Glide_result_parser.py │ │ ├── Ligprep_ligand_preparator.py │ │ ├── __init__.py │ │ └── license_token_guard.py │ ├── TautEnum │ │ ├── __init__.py │ │ └── taut_enum_smile_preparation.py │ ├── __init__.py │ ├── docker.py │ ├── factories │ │ ├── __init__.py │ │ └── transformator_factory.py │ ├── input_model.py │ ├── ligand │ │ ├── __init__.py │ │ ├── ligand.py │ │ └── ligand_input_parser.py │ ├── ligand_preparator.py │ ├── pdb_preparator.py │ ├── rDock │ │ ├── __init__.py │ │ ├── rDock_docker.py │ │ ├── rDock_result_parser.py │ │ └── rDock_target_preparator.py │ ├── result_parser.py │ ├── stereo_enumerator.py │ ├── target_preparator.py │ └── transformator.py ├── loggers │ ├── __init__.py │ ├── base_logger.py │ ├── blank_logger.py │ ├── docking_logger.py │ ├── interface_logger.py │ ├── ligand_preparation_logger.py │ └── target_preparation_logger.py └── utils │ ├── __init__.py │ ├── argparse_bool_extension.py │ ├── dockstream_exceptions.py │ ├── entry_point_functions │ ├── __init__.py │ ├── analysis.py │ ├── embedding.py │ ├── header.py │ └── write_out.py │ ├── enums │ ├── AutodockVina_enums.py │ ├── Corina_enums.py │ ├── Gold_enums.py │ ├── OE_Hybrid_enums.py │ ├── Omega_enums.py │ ├── OpenBabel_enums.py │ ├── OpenEye_enums.py │ ├── RDkit_enums.py │ ├── Schrodinger_enums.py │ ├── __init__.py │ ├── analysis_enums.py │ ├── docking_enum.py │ ├── ligand_preparation_enum.py │ ├── logging_enums.py │ ├── rDock_enums.py │ ├── stereo_enumeration_enums.py │ ├── tag_additions_enum.py │ ├── target_preparation_enum.py │ ├── taut_enum_enums.py │ └── transformations_enums.py │ ├── execute_external │ ├── AutodockVina.py │ ├── Corina.py │ ├── Gold.py │ ├── OE_Hybrid.py │ ├── Omega.py │ ├── OpenBabel.py │ ├── Schrodinger.py │ ├── TautEnum.py │ ├── __init__.py │ ├── execute.py │ └── rDock.py │ ├── files_paths.py │ ├── general_utils.py │ ├── parallelization │ ├── __init__.py │ └── general_utils.py │ ├── schema.py │ ├── smiles.py │ └── translations │ ├── __init__.py │ ├── molecule_translator.py │ └── translation.py ├── environment.yml ├── environment_full.yml ├── examples ├── docking │ ├── docking_csv_input.json │ ├── docking_sdf_input.json │ ├── parallelized_AutodockVina_enumerated.json │ ├── parallelized_Glide_enumerated.json │ ├── parallelized_Gold_enumerated.json │ ├── parallelized_Omega_Classic_Hybrid.json │ └── parallelized_rDock_enumerated.json ├── integration │ ├── AutoDock_Vina.json │ ├── Glide.json │ ├── OpenEyeHybrid.json │ └── rDock.json ├── ligand_preparation │ ├── corina_ligand_preparation.json │ ├── ligprep_ligand_preparation.json │ ├── omega_classic_ligand_preparation.json │ ├── rdkit_stereo.json │ └── taut_enum_all_backends.json └── target_preparation │ ├── AutoDockVina_target_preparation.json │ ├── Gold_target_preparation.json │ ├── OpenEye_target_preparation.json │ └── rDock_target_preparation.json ├── generate_json_schema.py ├── install_GOLD.txt ├── sample_user_input.json ├── sdf2smiles.py ├── setup.cfg ├── setup.py ├── smiles_clean_up.py ├── target_preparator.py ├── tests ├── AutodockVina │ ├── __init__.py │ ├── test_AutoDockVina_backend.py │ └── test_AutoDockVina_target_preparation.py ├── Corina │ ├── __init__.py │ └── test_Corina_ligand_preparation.py ├── Gold │ ├── __init__.py │ ├── test_Gold_backend.py │ └── test_Gold_target_preparation.py ├── Omega │ ├── __init__.py │ └── test_Omega_ligand_preparation.py ├── OpenEye │ ├── __init__.py │ ├── test_OpenEye_backend.py │ ├── test_OpenEye_ligand_preparation.py │ ├── test_OpenEye_target_preparation.py │ └── test_OpenEye_transformer.py ├── OpenEye_Hybrid │ ├── __init__.py │ └── test_OE_Hybrid_backend.py ├── RDkit │ ├── __init__.py │ ├── test_RDkit_ligand_preparation.py │ └── test_RDkit_stereo_enumeration.py ├── Schrodinger │ ├── __init__.py │ ├── test_Schrodinger_backend.py │ ├── test_ligprep_ligand_preparation.py │ └── test_token_guard.py ├── TautEnum │ ├── __init__.py │ └── test_TautEnum_functionality.py ├── __init__.py ├── ligand │ ├── __init__.py │ └── test_ligand_input_parser.py ├── rDock │ ├── __init__.py │ ├── test_rDock_backend.py │ └── test_rDock_target_preparation.py ├── test_PDBPreparation.py ├── test_input_model.py ├── test_ligand_preparation.py ├── tests_data │ ├── 1UYD │ │ ├── 1UYD_apo.mol2 │ │ ├── 1UYD_apo.pdb │ │ ├── 1UYD_apo_missing_parts.pdb │ │ ├── 1UYD_ligand_PU8.pdb │ │ ├── LICENSE_CITATION.txt │ │ ├── PU8.pdb │ │ ├── ligand_PU8.sdf │ │ ├── ligands.csv │ │ ├── ligands.sdf │ │ ├── ligands_aligned.sdf │ │ ├── ligands_aligned_tethered.sdf │ │ ├── ligands_smiles.txt │ │ ├── ligands_smiles_dup.txt │ │ ├── ligands_smiles_taut_enum.smi │ │ ├── ligands_taut_enum.csv │ │ ├── ligands_with_enumeration.sdf │ │ └── ligands_with_hydrogens.sdf │ ├── AutoDockVina │ │ └── 1UYD_fixed.pdbqt │ ├── Corina │ │ └── ligands.sdf │ ├── Gold │ │ └── Gold_binding_site.pkl │ ├── OpenEye │ │ └── 1UYD_reference_receptor.oeb │ ├── OpenEyeHybrid │ │ └── 1UYD_reference_receptor.oeb │ ├── Schrodinger │ │ ├── 1UYD_grid.zip │ │ ├── 1UYD_hbond_constraints.zip │ │ └── licadmin_output.txt │ └── rDock │ │ ├── output_ligands_tethered.sd │ │ ├── rbcavity_1UYD.prm │ │ ├── rbcavity_1UYD_updated.as │ │ ├── rbcavity_1UYD_updated.prm │ │ └── rbcavity_1UYD_updated_cav1.grd ├── tests_paths.py └── tests_translation.py └── unit_tests.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.pyc 3 | package.json 4 | .vscode 5 | tags 6 | .idea 7 | 8 | tests/junk 9 | !tests/junk/desc.txt 10 | 11 | dockstream/config/tests_config/config.json 12 | 13 | dockstream.log 14 | dockstream.err 15 | .directory 16 | -------------------------------------------------------------------------------- /DockStream.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/DockStream.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Please note: this repository is no longer being maintained.** 2 | 3 | # `DockStream` 4 | ![alt text](DockStream.jpg) 5 | 6 | ## Description 7 | DockStream is a docking wrapper providing access to a collection of ligand embedders and docking backends. 8 | Docking execution and post hoc analysis can be automated via the benchmarking and analysis workflow. The 9 | flexilibity to specifiy a large variety of docking configurations allows tailored protocols for diverse 10 | end applications. DockStream can also parallelize docking across CPU cores, increasing throughput. 11 | DockStream is integrated with the de novo design platform, [REINVENT](https://github.com/MolecularAI/Reinvent), 12 | allowing one to incorporate docking into the generative process, thus providing the agent with 3D 13 | structural information. 14 | 15 | ## Supported Backends 16 | ### Ligand Embedders 17 | * **[`RDKit`](https://www.rdkit.org/docs/GettingStartedInPython.html#working-with-3d-molecules)** 18 | * **[`Corina`](https://www.mn-am.com/products/corina)** 19 | * **[OpenEye's `OMEGA`](https://www.eyesopen.com/omega)** 20 | * **[Schrodinger's `LigPrep`](https://www.schrodinger.com/products/ligprep)** 21 | * **[`TautEnum`](https://github.com/OpenEye-Contrib/TautEnum/blob/master/README)** 22 | 23 | ### Docking Backends 24 | * **[`AutoDock Vina`](http://vina.scripps.edu/index.html)** 25 | * **[`rDock`](http://rdock.sourceforge.net)** 26 | * **[OpenEye's `Hybrid`](https://www.eyesopen.com/oedocking-tk)** 27 | * **[Schrodinger's `Glide`](https://www.schrodinger.com/glide)** 28 | * **[CCDC's `GOLD`](https://www.ccdc.cam.ac.uk/solutions/csd-discovery/components/gold)** 29 | 30 | Note: The `CCDC` package, the `OpenEye` toolkit and `Schrodinger`'s tools require you to obtain the respective software from those vendors. 31 | 32 | ## Tutorials and Usage 33 | Detailed `Jupyter Notebook` tutorials for all `DockStream` functionalities and workflows are provided in 34 | [DockStreamCommunity](https://github.com/MolecularAI/DockStreamCommunity). The `DockStream` repository here 35 | contains input `JSON` templates located in [examples](https://github.com/MolecularAI/DockStreamCommunity/examples). 36 | The templates are organized as follows: 37 | * `target_preparation`: Preparing targets for docking 38 | * `ligand_preparation`: Generating 3D coordinates for ligands 39 | * `docking`: Docking ligands 40 | * `integration`: Combining different ligand embedders and docking backends into a single input `JSON` to run successively 41 | 42 | ## Using DockStream in REINVENT 43 | DockStream provides a flexible implementation of molecular docking as a scoring function component in REINVENT. The generative 44 | agent is able to gradually generate compounds that satisfy the DockStream component, i.e, achieve favourable docking scores. 45 | A [tutorial notebook](https://github.com/MolecularAI/ReinventCommunity/blob/master/notebooks/Reinforcement_Learning_Demo_DockStream.ipynb) is provided. 46 | 47 | ## Requirements 48 | Two Conda environments are provided: `DockStream` via `environment.yml` and `DockStreamFull` via `environment_full.yml`. 49 | `DockStream` suffices for all use cases except when `CCDC GOLD` software is used, in which case `DockStreamFull` is required. 50 | ``` 51 | git clone 52 | cd 53 | conda env create -f environment.yml 54 | conda activate DockStream 55 | ``` 56 | 57 | ## Enable use of OpenEye software (from [REINVENT README](https://github.com/MolecularAI/Reinvent)) 58 | You will need to set the environmental variable OE_LICENSE to activate the oechem license. 59 | One way to do this and keep it conda environment specific is: 60 | On the command-line, first: 61 | 62 | ``` 63 | cd $CONDA_PREFIX 64 | mkdir -p ./etc/conda/activate.d 65 | mkdir -p ./etc/conda/deactivate.d 66 | touch ./etc/conda/activate.d/env_vars.sh 67 | touch ./etc/conda/deactivate.d/env_vars.sh 68 | ``` 69 | 70 | Then edit ```./etc/conda/activate.d/env_vars.sh``` as follows: 71 | 72 | ``` 73 | #!/bin/sh 74 | export OE_LICENSE='/opt/scp/software/oelicense/1.0/oe_license.seq1' 75 | ``` 76 | 77 | and finally, edit ./etc/conda/deactivate.d/env_vars.sh : 78 | 79 | ``` 80 | #!/bin/sh 81 | unset OE_LICENSE 82 | ``` 83 | 84 | ## Unit Tests 85 | After cloning the `DockStream` repository, enable licenses, if applicable (`OpenEye`, `CCDC`, `Schrodinger`). Then execute the following: 86 | ``` 87 | python unit_tests.py 88 | ``` 89 | 90 | ## Contributors 91 | Christian Margreitter (christian.margreitter@astrazeneca.com) 92 | Jeff Guo (jeff.guo@astrazeneca.com) 93 | Alexey Voronov (alexey.voronov1@astrazeneca.com) 94 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | # import the containers (effectively python dictionaries) 2 | 3 | # make all Enums accessible 4 | 5 | # rDock 6 | # --------- 7 | 8 | # OpenEye 9 | # --------- 10 | -------------------------------------------------------------------------------- /benchmarking.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import errno 4 | import sys 5 | import argparse 6 | 7 | from dockstream.utils.execute_external.execute import Executor 8 | from dockstream.utils import files_paths 9 | from dockstream.utils.enums.docking_enum import DockingConfigurationEnum 10 | 11 | _DC = DockingConfigurationEnum() 12 | 13 | 14 | def run_script(input_path: str) -> dict: 15 | """this method takes an input path to either a folder containing DockStream json files or a single json file and 16 | returns a dictionary whose keys are the json names and the corresponding values are the paths to the json 17 | file. The dictionary will be looped later to run DockStream 18 | 19 | :param input_path: path to either a folder of json files or a single json file 20 | :raises FileNotFoundError: this error is raised if input_path is neither a folder nor a file 21 | :return: dictionary, keys are the DockStream json names and values are the paths to them 22 | """ 23 | 24 | # first check if input_path is valid (either a folder containing json files or a single json file) 25 | if not os.path.isdir(input_path) and not os.path.isfile(input_path): 26 | raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), input_path) 27 | # if input_path is a folder, ensure it is not empty and that it contains at least 1 json file 28 | if os.path.isdir(input_path): 29 | if not os.listdir(input_path): 30 | sys.exit(input_path + ' folder is empty. Please ensure your DockStream json files are added to the folder.') 31 | elif not any(file.endswith('.json') for file in os.listdir(input_path)): 32 | sys.exit(input_path + ' contains no json files. Please ensure your DockStream json files are added to the folder.') 33 | # at this point, the path must be a file. Check that it is in json format 34 | if os.path.isfile(input_path): 35 | if not input_path.endswith('.json'): 36 | sys.exit(input_path + ' is not a json file. Please ensure it is in json format.') 37 | 38 | # initialize a dictionary to hold all DockStream runs 39 | batch_runs = {} 40 | # loop through all json files and update the paths if input_path if a directory 41 | if os.path.isdir(input_path): 42 | all_runs = [file for file in os.listdir(input_path) if file.endswith('.json')] 43 | for json in all_runs: 44 | batch_runs[json.replace('.json', '')] = os.path.join(input_path, json) 45 | 46 | # at this point, input path must be a single json file 47 | else: 48 | json_name = os.path.basename(os.path.normpath(input_path)).replace('.json', '') 49 | batch_runs[json_name] = input_path 50 | 51 | return batch_runs 52 | 53 | 54 | if __name__ == '__main__': 55 | # take user specified input parameters to run the benchmarking script 56 | parser = argparse.ArgumentParser(description='Facilitates batch DockStream execution.') 57 | parser.add_argument('-input_path', type=str, required=True, help='The path to either a folder of DockStream json files or a single json file.') 58 | args = parser.parse_args() 59 | 60 | batch_runs = run_script(args.input_path) 61 | 62 | executor = Executor() 63 | # initialize a dictionary to store the names of all runs that did not enforce "best_per_ligand" 64 | non_bpl_runs = {} 65 | # loop through all user json files and run DockStream 66 | for trial_name, json_path in batch_runs.items(): 67 | # check if the current DockStream run has "best_per_ligand" enforced 68 | with open(json_path, "r") as f: 69 | parameters = json.load(f) 70 | # in case output mode was not specified in the configuration json 71 | try: 72 | for docking_run in parameters[_DC.DOCKING][_DC.DOCKING_RUNS]: 73 | output_mode = docking_run[_DC.OUTPUT][_DC.OUTPUT_SCORES][_DC.OUTPUT_MODE] 74 | if output_mode != _DC.OUTPUT_MODE_BESTPERLIGAND: 75 | non_bpl_runs[trial_name] = output_mode 76 | break 77 | except: 78 | pass 79 | 80 | print(f'Running {trial_name}') 81 | 82 | result = executor.execute(command=sys.executable, arguments=[files_paths.attach_root_path('docker.py'), 83 | '-conf', json_path, '-debug'], check=False) 84 | 85 | print(result) 86 | # print out error messages (if applicable) for the current DockStream run 87 | if result.returncode != 0: 88 | print(f'There was an error with {trial_name} DockStream run.') 89 | print(result.stdout) 90 | print(result.stderr) 91 | 92 | if bool(non_bpl_runs): 93 | # print the names of the runs which did not enforce "best_per_ligand" 94 | print(f"List of runs which did not have 'best_per_ligand' specified. These runs cannot be " 95 | f"passed into the analysis script. {non_bpl_runs}") 96 | -------------------------------------------------------------------------------- /dockstream/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/__init__.py -------------------------------------------------------------------------------- /dockstream/analysis.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | import pandas as pd 4 | import numpy as np 5 | from sklearn.linear_model import LinearRegression 6 | from scipy.stats import spearmanr 7 | from scipy.stats import kendalltau 8 | from matplotlib import pyplot as plt 9 | import seaborn as sns 10 | 11 | 12 | def to_scatter_plot(file_name: str, docking_scores: np.ndarray, experimental_scores: np.ndarray): 13 | 14 | sns.set() 15 | plt.scatter(docking_scores, experimental_scores, color='g') 16 | plt.title(file_name + ' Scatter Plot') 17 | plt.xlabel('Docking Score (-kcal/mol)') 18 | plt.ylabel('Experimental Binding (-kcal/mol)') 19 | plt.savefig(file_name.replace('csv', ''), dpi=300) 20 | plt.figure() 21 | 22 | 23 | def output_analysis(data_dir: str, exp_data_path: str, output_dir: str) -> dict: 24 | 25 | docking_results = [file for file in os.listdir(data_dir) if file.endswith('.csv')] 26 | analysis_results = {} 27 | 28 | for file_name in docking_results: 29 | data_path = os.path.join(data_dir, file_name) 30 | # load the docking results 31 | docking_data = pd.read_csv(data_path) 32 | # load the experimental comparison data 33 | experimental_data = pd.read_csv(exp_data_path) 34 | # merge the docking results and experimental binding data based on their 'smiles' identifiers. 35 | # this is to ensure that data pertaining to the correct 'smiles' ligands are compared irrespective 36 | # of the order in which the user provides the experimental data 37 | comparison_df = docking_data.merge(experimental_data, on='smiles') 38 | 39 | # extract the DockStream docking scores and experimental potency parameter columns 40 | docking_scores = comparison_df['score'].to_numpy().reshape(-1,1) 41 | experimental_data = comparison_df['exp_binding'].to_numpy() 42 | # fit a linear model using least squares 43 | model = LinearRegression().fit(docking_scores, experimental_data) 44 | coeff_determination = model.score(docking_scores, experimental_data) 45 | # perform Spearman correlation analysis 46 | spearman_correlation = spearmanr(docking_scores, experimental_data) 47 | # perform Kendall correlation analysis 48 | kendall_correlation = kendalltau(docking_scores, experimental_data) 49 | # store the linear model and spearman quantities in a dictionary 50 | analysis_results[file_name] = {'coefficient of determination': coeff_determination, 'Spearman correlation': 51 | spearman_correlation, 'Kendall correlation': kendall_correlation} 52 | 53 | # call to_scatter_plot to create a scatter plot of docking_scores against experimental_data 54 | output_path = os.path.join(output_dir, file_name) 55 | to_scatter_plot(output_path, docking_scores, experimental_data) 56 | 57 | return analysis_results 58 | 59 | 60 | if __name__ == '__main__': 61 | # take user specified input parameters to run the analysis script 62 | parser = argparse.ArgumentParser(description='Implements entry point to results analysis.') 63 | parser.add_argument('-data_dir', type=str, required=True, help='The path to the output csv files to be analyzed.') 64 | parser.add_argument('-exp_data_path', type=str, required=True, help='The path to the experimental binding data of your ligand library. This will be used for regression analysis.') 65 | parser.add_argument('-output_dir', type=str, required=True, help='The desired output folder path to store the analyzed results and plots.') 66 | #parser.add_argument('-regression_threshold', type=int, default=0.75, help='The desired regression threshold to classify good/poor backend performances based on your receptor-ligand system. The default value if not specified is 0.75.') 67 | args = parser.parse_args() 68 | 69 | analysis_results = output_analysis(args.data_dir, args.exp_data_path, args.output_dir) 70 | -------------------------------------------------------------------------------- /dockstream/config/logging/debug.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "disable_existing_loggers": false, 4 | "formatters": { 5 | "standard": { 6 | "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s", 7 | "datefmt": "%Y-%m-%d %H:%M:%S" 8 | }, 9 | "blank": { 10 | "format": "%(message)s" 11 | } 12 | }, 13 | 14 | "handlers": { 15 | "console": { 16 | "class": "logging.StreamHandler", 17 | "level": "DEBUG", 18 | "formatter": "standard", 19 | "stream": "ext://sys.stderr" 20 | }, 21 | 22 | "file_handler": { 23 | "class": "logging.handlers.RotatingFileHandler", 24 | "level": "DEBUG", 25 | "formatter": "standard", 26 | "filename": "dockstream.log", 27 | "maxBytes": 10485760, 28 | "backupCount": 20, 29 | "encoding": "utf8" 30 | }, 31 | 32 | "file_handler_blank": { 33 | "class": "logging.handlers.RotatingFileHandler", 34 | "level": "DEBUG", 35 | "formatter": "blank", 36 | "filename": "dockstream.log", 37 | "maxBytes": 10485760, 38 | "backupCount": 20, 39 | "encoding": "utf8" 40 | } 41 | }, 42 | 43 | "loggers": { 44 | "command_line_interface": { 45 | "level": "DEBUG", 46 | "handlers": ["file_handler"], 47 | "propagate": false 48 | }, 49 | "target_preparation": { 50 | "level": "DEBUG", 51 | "handlers": ["file_handler"], 52 | "propagate": false 53 | }, 54 | "ligand_preparation": { 55 | "level": "DEBUG", 56 | "handlers": ["file_handler"], 57 | "propagate": false 58 | }, 59 | "docking": { 60 | "level": "DEBUG", 61 | "handlers": ["file_handler"], 62 | "propagate": false 63 | }, 64 | "blank": { 65 | "level": "DEBUG", 66 | "handlers": ["file_handler_blank"], 67 | "propagate": false 68 | } 69 | }, 70 | 71 | "root": { 72 | "level": "DEBUG", 73 | "handlers": ["file_handler"] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /dockstream/config/logging/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "disable_existing_loggers": false, 4 | "formatters": { 5 | "standard": { 6 | "format": "%(asctime)s - %(message)s", 7 | "datefmt": "%Y-%m-%d %H:%M:%S" 8 | }, 9 | "blank": { 10 | "format": "%(message)s" 11 | } 12 | }, 13 | 14 | "handlers": { 15 | "console": { 16 | "class": "logging.StreamHandler", 17 | "level": "INFO", 18 | "formatter": "standard", 19 | "stream": "ext://sys.stderr" 20 | }, 21 | 22 | "file_handler": { 23 | "class": "logging.handlers.RotatingFileHandler", 24 | "level": "INFO", 25 | "formatter": "standard", 26 | "filename": "dockstream.log", 27 | "maxBytes": 10485760, 28 | "backupCount": 20, 29 | "encoding": "utf8" 30 | }, 31 | 32 | "file_handler_blank": { 33 | "class": "logging.handlers.RotatingFileHandler", 34 | "level": "INFO", 35 | "formatter": "blank", 36 | "filename": "dockstream.log", 37 | "maxBytes": 10485760, 38 | "backupCount": 20, 39 | "encoding": "utf8" 40 | } 41 | }, 42 | 43 | "loggers": { 44 | "command_line_interface": { 45 | "level": "INFO", 46 | "handlers": ["file_handler"], 47 | "propagate": false 48 | }, 49 | "target_preparation": { 50 | "level": "INFO", 51 | "handlers": ["file_handler"], 52 | "propagate": false 53 | }, 54 | "ligand_preparation": { 55 | "level": "INFO", 56 | "handlers": ["file_handler"], 57 | "propagate": false 58 | }, 59 | "docking": { 60 | "level": "INFO", 61 | "handlers": ["file_handler"], 62 | "propagate": false 63 | }, 64 | "blank": { 65 | "level": "INFO", 66 | "handlers": ["file_handler_blank"], 67 | "propagate": false 68 | } 69 | }, 70 | 71 | "root": { 72 | "level": "INFO", 73 | "handlers": ["file_handler"] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /dockstream/config/logging/verbose.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "disable_existing_loggers": false, 4 | "formatters": { 5 | "standard": { 6 | "format": "%(asctime)s - %(message)s", 7 | "datefmt": "%Y-%m-%d %H:%M:%S" 8 | }, 9 | "blank": { 10 | "format": "%(message)s" 11 | } 12 | }, 13 | 14 | "handlers": { 15 | "console": { 16 | "class": "logging.StreamHandler", 17 | "level": "INFO", 18 | "formatter": "standard", 19 | "stream": "ext://sys.stderr" 20 | }, 21 | 22 | "file_handler": { 23 | "class": "logging.handlers.RotatingFileHandler", 24 | "level": "INFO", 25 | "formatter": "standard", 26 | "filename": "dockstream.log", 27 | "maxBytes": 10485760, 28 | "backupCount": 20, 29 | "encoding": "utf8" 30 | }, 31 | 32 | "file_handler_blank": { 33 | "class": "logging.handlers.RotatingFileHandler", 34 | "level": "INFO", 35 | "formatter": "blank", 36 | "filename": "dockstream.log", 37 | "maxBytes": 10485760, 38 | "backupCount": 20, 39 | "encoding": "utf8" 40 | } 41 | }, 42 | 43 | "loggers": { 44 | "command_line_interface": { 45 | "level": "INFO", 46 | "handlers": ["file_handler"], 47 | "propagate": false 48 | }, 49 | "target_preparation": { 50 | "level": "INFO", 51 | "handlers": ["file_handler"], 52 | "propagate": false 53 | }, 54 | "ligand_preparation": { 55 | "level": "INFO", 56 | "handlers": ["file_handler"], 57 | "propagate": false 58 | }, 59 | "docking": { 60 | "level": "INFO", 61 | "handlers": ["file_handler"], 62 | "propagate": false 63 | }, 64 | "blank": { 65 | "level": "INFO", 66 | "handlers": ["file_handler_blank"], 67 | "propagate": false 68 | } 69 | }, 70 | 71 | "root": { 72 | "level": "INFO", 73 | "handlers": ["file_handler"] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /dockstream/config/rDock/standard_reference_ligand.prm: -------------------------------------------------------------------------------- 1 | RBT_PARAMETER_FILE_V1.00 2 | TITLE rDock_default_cavity_reference_ligand 3 | 4 | RECEPTOR_FILE 5 | RECEPTOR_FLEX 3.0 6 | 7 | ################################################################## 8 | ### CAVITY DEFINITION: REFERENCE LIGAND METHOD 9 | ################################################################## 10 | SECTION MAPPER 11 | SITE_MAPPER RbtLigandSiteMapper 12 | REF_MOL 13 | RADIUS 6.0 14 | SMALL_SPHERE 1.0 15 | MIN_VOLUME 100 16 | MAX_CAVITIES 1 17 | VOL_INCR 0.0 18 | GRIDSTEP 0.5 19 | END_SECTION 20 | 21 | ################################# 22 | #CAVITY RESTRAINT PENALTY 23 | ################################# 24 | SECTION CAVITY 25 | SCORING_FUNCTION RbtCavityGridSF 26 | WEIGHT 1.0 27 | END_SECTION 28 | -------------------------------------------------------------------------------- /dockstream/config/tests_config/example.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "OE_LICENSE": "/opt/scp/software/oelicense/1.0/oe_license.seq1", 3 | "CSDHOME": "/opt/scp/software/ccdc/2020.0.1/CSD_2020" 4 | } -------------------------------------------------------------------------------- /dockstream/containers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/containers/__init__.py -------------------------------------------------------------------------------- /dockstream/containers/analysis_container.py: -------------------------------------------------------------------------------- 1 | from dockstream.containers.container import ConfigurationContainer 2 | 3 | 4 | class AnalysisContainer(ConfigurationContainer): 5 | """Class that takes a lot of arguments in the form of a JSON configuration (as dictionary, string or file path) 6 | and, optionally, performs a JSON Schema validation.""" 7 | 8 | def __init__(self, conf, validation=True): 9 | super().__init__(conf=conf) 10 | 11 | # TODO: include validation with JSON Schema 12 | if validation: 13 | self.validate() 14 | 15 | def validate(self): 16 | pass 17 | # load the Schema 18 | #path = os.path.join(files_paths.move_up_directory(__file__, 1), 19 | # "docking", "json_schemas", 20 | # "BuildingConfiguration.json") 21 | #schema = load_json.loadJSON(path=path) 22 | 23 | # instantiate validator and perform the check 24 | #validator = Draft7Validator(schema=schema) 25 | #validator.validate(self._conf) 26 | -------------------------------------------------------------------------------- /dockstream/containers/container.py: -------------------------------------------------------------------------------- 1 | import abc 2 | import json 3 | import os 4 | 5 | 6 | class ConfigurationContainer(object, metaclass=abc.ABCMeta): 7 | """Class that takes a lot of arguments in the form of a JSON configuration (as dictionary, string or file path) 8 | and, optionally, performs a JSON Schema validation.""" 9 | 10 | @abc.abstractmethod 11 | def __init__(self, conf): 12 | # get instance of configuration enum and load configuration 13 | # parameter "config" can be a string, a path or a dictionary (as long as it holds valid JSON input) 14 | if isinstance(conf, str): 15 | if os.path.isfile(conf): 16 | with open(conf) as file: 17 | conf = file.read().replace("\r", "").replace("\n", "") 18 | conf = json.loads(conf) 19 | self._conf = conf 20 | 21 | def get_as_dict(self): 22 | return self._conf 23 | 24 | def get(self, key, default=None): 25 | return self._conf.get(key, default) 26 | 27 | def __getitem__(self, item): 28 | return self.get_as_dict()[item] 29 | 30 | def get_as_string(self): 31 | return json.dumps(self._conf) 32 | 33 | def validate(self): 34 | raise NotImplementedError("This functions needs to be implemented by child classes.") 35 | -------------------------------------------------------------------------------- /dockstream/containers/docking_container.py: -------------------------------------------------------------------------------- 1 | from dockstream.containers.container import ConfigurationContainer 2 | 3 | 4 | class DockingContainer(ConfigurationContainer): 5 | """Class that takes a lot of arguments in the form of a JSON configuration (as dictionary, string or file path) 6 | and, optionally, performs a JSON Schema validation.""" 7 | 8 | def __init__(self, conf, validation=True): 9 | super().__init__(conf=conf) 10 | 11 | # TODO: include validation with JSON Schema 12 | if validation: 13 | self.validate() 14 | 15 | def validate(self): 16 | pass 17 | # load the Schema 18 | #path = os.path.join(files_paths.move_up_directory(__file__, 1), 19 | # "docking", "json_schemas", 20 | # "BuildingConfiguration.json") 21 | #schema = load_json.loadJSON(path=path) 22 | 23 | # instantiate validator and perform the check 24 | #validator = Draft7Validator(schema=schema) 25 | #validator.validate(self._conf) 26 | -------------------------------------------------------------------------------- /dockstream/containers/target_preparation_container.py: -------------------------------------------------------------------------------- 1 | from dockstream.containers.container import ConfigurationContainer 2 | 3 | 4 | class TargetPreparationContainer(ConfigurationContainer): 5 | """Class that takes a lot of arguments in the form of a JSON configuration (as dictionary, string or file path) 6 | and, optionally, performs a JSON Schema validation.""" 7 | 8 | def __init__(self, conf, validation=True): 9 | super().__init__(conf=conf) 10 | 11 | # TODO: include validation with JSON Schema 12 | if validation: 13 | self.validate() 14 | 15 | def validate(self): 16 | pass 17 | # load the Schema 18 | #path = os.path.join(files_paths.move_up_directory(__file__, 1), 19 | # "docking", "json_schemas", 20 | # "BuildingConfiguration.json") 21 | #schema = load_json.loadJSON(path=path) 22 | 23 | # instantiate validator and perform the check 24 | #validator = Draft7Validator(schema=schema) 25 | #validator.validate(self._conf) 26 | -------------------------------------------------------------------------------- /dockstream/core/AutodockVina/AutodockVina_result_parser.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from dockstream.core.result_parser import ResultParser 3 | 4 | from dockstream.utils.enums.AutodockVina_enums import AutodockResultKeywordsEnum 5 | 6 | 7 | class AutodockResultParser(ResultParser): 8 | """Class that loads, parses and analyzes the output of an "AutoDock Vina" docking run, including poses and scores.""" 9 | def __init__(self, ligands): 10 | super().__init__(ligands=ligands) 11 | self._RK = AutodockResultKeywordsEnum() 12 | 13 | self._df_results = self._construct_dataframe() 14 | 15 | def _construct_dataframe(self) -> pd.DataFrame: 16 | def func_get_score(conformer): 17 | return float(conformer.GetProp(self._RK.SDF_TAG_SCORE)) 18 | 19 | return super()._construct_dataframe_with_funcobject(func_get_score) 20 | -------------------------------------------------------------------------------- /dockstream/core/AutodockVina/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/core/AutodockVina/__init__.py -------------------------------------------------------------------------------- /dockstream/core/Corina/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/core/Corina/__init__.py -------------------------------------------------------------------------------- /dockstream/core/Gold/Gold_result_parser.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from dockstream.core.result_parser import ResultParser 3 | 4 | from dockstream.utils.enums.Gold_enums import GoldOutputEnum, GoldDockingConfigurationEnum 5 | 6 | 7 | class GoldResultParser(ResultParser): 8 | """Class that loads, parses and analyzes the output of a "Gold" docking run, including poses and scores.""" 9 | def __init__(self, ligands: list, fitness_function: str, response_value="fitness"): 10 | super().__init__(ligands=ligands) 11 | self._ROE = GoldOutputEnum() 12 | self._DE = GoldDockingConfigurationEnum() 13 | 14 | self._fitness_function = fitness_function 15 | self._response_value = response_value 16 | self._df_results = self._construct_dataframe() 17 | 18 | def _get_scoring_function_parameters(self): 19 | # get the appropriate name of the tag and whether mininmal or maximal values are best for 20 | # the specified scoring function 21 | if self._response_value == self._DE.GOLD_RESPONSE_VALUE_FITNESS: 22 | scoring_function_parameters = self._ROE.DICT_FITNESS[self._fitness_function] 23 | elif self._response_value == self._DE.GOLD_RESPONSE_VALUE_VALUE: 24 | scoring_function_parameters = self._ROE.DICT_VALUE[self._fitness_function] 25 | else: 26 | raise ValueError("Parameter response value must be either fitness or value.") 27 | self._logger.log(f"Set scoring_function_parameters to {scoring_function_parameters} for result parsing.", 28 | self._LE.DEBUG) 29 | return scoring_function_parameters 30 | 31 | def _construct_dataframe(self) -> pd.DataFrame: 32 | scoring_function_parameters = self._get_scoring_function_parameters() 33 | 34 | def func_get_score(conformer): 35 | return float(conformer.GetProp(scoring_function_parameters[self._ROE.TAG])) 36 | 37 | return super()._construct_dataframe_with_funcobject(func_get_score) 38 | -------------------------------------------------------------------------------- /dockstream/core/Gold/Gold_target_preparator.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pickle 3 | import ccdc 4 | from ccdc.docking import Docker 5 | from ccdc.io import MoleculeReader 6 | 7 | from dockstream.core.target_preparator import TargetPreparator 8 | 9 | from dockstream.utils.dockstream_exceptions import TargetPreparationFailed 10 | 11 | from dockstream.utils.enums.Gold_enums import GoldTargetPreparationEnum, GoldTargetKeywordEnum 12 | from dockstream.containers.target_preparation_container import TargetPreparationContainer 13 | 14 | 15 | class GoldTargetPreparator(TargetPreparator): 16 | """Class that deals with all the target preparatory steps needed before docking using "GOLD" can commence.""" 17 | 18 | def __init__(self, conf: TargetPreparationContainer, target, run_number=0): 19 | self._TP = GoldTargetPreparationEnum() 20 | self._TK = GoldTargetKeywordEnum() 21 | self._target_dict = {self._TK.VERSION: self._TK.CURRENT_VERSION} 22 | 23 | # invoke base class's constructor first 24 | super().__init__(conf=conf, run_number=run_number) 25 | 26 | # check, whether the backend run specified is an "GOLD" one 27 | if self._run_parameters[self._TP.RUNS_BACKEND] != self._TP.RUNS_BACKEND_GOLD: 28 | raise TargetPreparationFailed("Tried to make an GOLD preparation with different backend specification.") 29 | 30 | if isinstance(target, str): 31 | if os.path.isfile(target): 32 | _, file_extension = os.path.splitext(target) 33 | if file_extension == ".pdb": 34 | self._target = Docker() 35 | self._settings = self._target.settings 36 | self._settings.add_protein_file(file_name=target) 37 | 38 | # add information to dictionary 39 | with open(target, 'r') as file: 40 | self._target_dict[self._TK.TARGET_PDB] = [line for line in file] 41 | self._target_dict[self._TK.TARGET_PDB_FILENAME] = os.path.basename(target) 42 | else: 43 | raise TargetPreparationFailed("Specified input file must be in PDB format for GOLD.") 44 | else: 45 | raise TargetPreparationFailed("Input target file does not exist.") 46 | elif isinstance(target, ccdc.docking.Docker): 47 | raise NotImplementedError 48 | else: 49 | raise TargetPreparationFailed("Constructor only accepts and Protein.BindingSite object or a file path.") 50 | self._logger.log("Added target to GOLD settings.", self._TL.DEBUG) 51 | 52 | def specify_cavity(self): 53 | self._target_dict[self._TK.CAVITY_METHOD] = self._run_parameters[self._TP.CAVITY][self._TP.CAVITY_METHOD] 54 | if self._run_parameters[self._TP.CAVITY][self._TP.CAVITY_METHOD] == self._TP.CAVITY_METHOD_REFERENCE: 55 | # note, that "MoleculeReader" is able to discern many formats from the ending, including "mol2" and "pdb" 56 | ref_ligand_path = self._run_parameters[self._TP.CAVITY][self._TP.CAVITY_REFERENCE_PATH] 57 | ref_ligand = MoleculeReader(filename=ref_ligand_path) 58 | protein = self._settings.proteins[0] 59 | self._settings.binding_site = self._settings.BindingSiteFromLigand(protein, ref_ligand, distance=self._run_parameters[self._TP.CAVITY][self._TP.CAVITY_REFERENCE_DISTANCE]) 60 | 61 | # add information to dictionary 62 | with open(ref_ligand_path, 'r') as file: 63 | self._target_dict[self._TK.REFERENCE_LIGAND] = [line for line in file] 64 | self._target_dict[self._TK.CAVITY_REFERENCE_DISTANCE] = self._run_parameters[self._TP.CAVITY][self._TP.CAVITY_REFERENCE_DISTANCE] 65 | self._target_dict[self._TK.REFERENCE_LIGAND_FILENAME] = os.path.basename(ref_ligand_path) 66 | elif self._run_parameters[self._TP.CAVITY][self._TP.CAVITY_METHOD] == self._TP.CAVITY_METHOD_POINT: 67 | raise NotImplementedError 68 | # origin (x,x,x) 69 | # distance x 70 | else: 71 | raise TargetPreparationFailed("Specified cavity determination method not defined for GOLD.") 72 | self._logger.log(f"Generated GOLD Protein.BindingSite with method {self._run_parameters[self._TP.CAVITY][self._TP.CAVITY_METHOD]}.", self._TL.DEBUG) 73 | 74 | def write_target(self, path): 75 | _, file_extension = os.path.splitext(path) 76 | if file_extension != ".pkl": 77 | raise TargetPreparationFailed("Receptor files must end on .pkl.") 78 | if self._TK.CAVITY_METHOD not in self._target_dict: 79 | self._logger.log("Need to have executed specify_cavity before writing out result - will attempt this now.", self._TL.WARNING) 80 | self.specify_cavity() 81 | with open(path, "wb") as f: 82 | pickle.dump(self._target_dict, f) 83 | self._logger.log(f"Wrote binding site to file {path}.", self._TL.DEBUG) 84 | -------------------------------------------------------------------------------- /dockstream/core/Gold/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/core/Gold/__init__.py -------------------------------------------------------------------------------- /dockstream/core/OpenEye/OpenEye_result_parser.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from dockstream.core.result_parser import ResultParser 3 | 4 | from dockstream.utils.enums.OpenEye_enums import OpenEyeResultKeywordsEnum 5 | 6 | 7 | class OpenEyeResultParser(ResultParser): 8 | """Class that loads, parses and analyzes the output of an "OpenEye" docking run, including poses and scores.""" 9 | def __init__(self, ligands: list): 10 | super().__init__(ligands=ligands) 11 | self._RK = OpenEyeResultKeywordsEnum() 12 | 13 | self._df_results = self._construct_dataframe() 14 | 15 | def _construct_dataframe(self) -> pd.DataFrame: 16 | def func_get_score(conformer): 17 | return float(conformer.GetEnergy()) 18 | 19 | return super()._construct_dataframe_with_funcobject(func_get_score) 20 | -------------------------------------------------------------------------------- /dockstream/core/OpenEye/OpenEye_transformator.py: -------------------------------------------------------------------------------- 1 | import openeye.oechem as oechem 2 | 3 | from dockstream.utils.dockstream_exceptions import LigandPreparationFailed, TransformationFailed 4 | 5 | from dockstream.utils.enums.OpenEye_enums import OpenEyeDockingConfigurationEnum, OpenEyeLigandPreparationEnum 6 | from dockstream.core.transformator import Transformator 7 | 8 | 9 | class OpenEyeTransformator(Transformator): 10 | """Class that applies SMIRKS (OpenEye style) to compounds before they are further processed.""" 11 | 12 | def __init__(self, conf): 13 | super().__init__(conf) 14 | self._LP = OpenEyeLigandPreparationEnum() 15 | self._CE = OpenEyeDockingConfigurationEnum() 16 | 17 | def transform(self, ligands) -> list: 18 | number_input = len(ligands) 19 | failed_indices = [] 20 | 21 | # code based on Graeme Robb's scrip 22 | if self._type == self._TE.TRANSFORMATION_TYPE_SMIRKS: 23 | rxn = oechem.OEUniMolecularRxn(self._smirk) 24 | 25 | for ligand_number, ligand in enumerate(ligands): 26 | try: 27 | molecule = oechem.OEMol() 28 | oechem.OESmilesToMol(molecule, ligand.get_smile()) 29 | 30 | # apply the smirk 31 | oechem.OEAddExplicitHydrogens(molecule) 32 | success = rxn(molecule) 33 | if success: 34 | ligand.set_smile(oechem.OEMolToSmiles(molecule)) 35 | else: 36 | raise TransformationFailed 37 | except Exception as e: 38 | failed_indices.append(ligand_number) 39 | 40 | if self._fail_action == self._TE.TRANSFORMATION_FAIL_ACTION_DISCARD: 41 | failed_indices.reverse() 42 | for index in failed_indices: 43 | self._logger.log(f"Failed transformation, discarding ligand with smile {ligands[index].get_smile()}.", self._LE.DEBUG) 44 | del ligands[index] 45 | else: 46 | self._logger.log(f"For transformation backend {self._backend}, only type {self._TE.TRANSFORMATION_TYPE_SMIRKS} is supported.", self._LE.ERROR) 47 | raise LigandPreparationFailed(f"For transformation backend {self._backend}, only type {self._TE.TRANSFORMATION_TYPE_SMIRKS} is supported.") 48 | 49 | self._logger.log(f"Of {number_input} input smiles, {len(ligands)} smiles were transformed / retained ({len(failed_indices)} transformations failed with \"fail_action\" set to {self._fail_action}).", self._LE.DEBUG) 50 | for ligand in ligands: 51 | self._logger_blank.log(ligand.get_smile(), self._LE.DEBUG) 52 | return ligands 53 | -------------------------------------------------------------------------------- /dockstream/core/OpenEye/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/core/OpenEye/__init__.py -------------------------------------------------------------------------------- /dockstream/core/OpenEyeHybrid/OpenEyeHybrid_result_parser.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from dockstream.core.result_parser import ResultParser 3 | 4 | from dockstream.utils.enums.OE_Hybrid_enums import OpenEyeHybridOutputKeywordsEnum 5 | 6 | 7 | class OpenEyeHybridResultParser(ResultParser): 8 | """Loads, parses and analyzes the output of an "OpenEye Hybrid" docking run, including poses and score.""" 9 | def __init__(self, ligands: list): 10 | super().__init__(ligands=ligands) 11 | self._OE = OpenEyeHybridOutputKeywordsEnum() 12 | self._df_results = self._construct_dataframe() 13 | 14 | def _construct_dataframe(self) -> pd.DataFrame: 15 | def func_get_score(conformer): 16 | return float(conformer.GetProp(self._OE.SCORE)) 17 | 18 | return super()._construct_dataframe_with_funcobject(func_get_score) 19 | -------------------------------------------------------------------------------- /dockstream/core/RDkit/RDkit_stereo_enumerator.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy 2 | from typing import Optional, List 3 | 4 | from typing_extensions import Literal 5 | 6 | from pydantic import BaseModel 7 | from rdkit import Chem 8 | from rdkit.Chem.EnumerateStereoisomers import EnumerateStereoisomers, StereoEnumerationOptions 9 | 10 | from dockstream.core.stereo_enumerator import StereoEnumerator 11 | from dockstream.core.ligand.ligand import Ligand, get_next_enumeration_number_for_ligand 12 | 13 | 14 | class RDKitStereoEnumeratorParameters(BaseModel): 15 | try_embedding: bool = True 16 | unique: bool = True 17 | max_isomers: int = 1024 18 | rand: Optional[int] = 0xf00d 19 | 20 | 21 | class RDKitStereoEnumerator(StereoEnumerator, BaseModel): 22 | 23 | backend: Literal["RDKit"] = "RDKit" 24 | parameters: RDKitStereoEnumeratorParameters = RDKitStereoEnumeratorParameters() 25 | 26 | def __init__(self, **data): 27 | super().__init__(**data) 28 | 29 | def enumerate(self, ligands: List[Ligand]) -> List[Ligand]: 30 | new_ligands_list = [] 31 | opts = StereoEnumerationOptions(tryEmbedding=self.parameters.try_embedding, 32 | unique=self.parameters.unique, 33 | maxIsomers=self.parameters.max_isomers, 34 | rand=self.parameters.rand) 35 | for ligand in ligands: 36 | molecule = Chem.MolFromSmiles(ligand.get_smile()) 37 | if not molecule: 38 | # could not build molecule, keep the original ligand 39 | new_ligands_list.append(deepcopy(ligand)) 40 | continue 41 | 42 | isomers = tuple(EnumerateStereoisomers(molecule, options=opts)) 43 | if len(isomers) == 0: 44 | # could not enumerate, keep original ligand 45 | new_ligands_list.append(deepcopy(ligand)) 46 | continue 47 | 48 | # loop over stereo-isomers, translate them into smiles and create new ligand objects from them 49 | for new_smile_id, new_smile in enumerate(sorted(Chem.MolToSmiles(x, isomericSmiles=True) for x in isomers)): 50 | new_ligands_list.append(Ligand(smile=new_smile, 51 | original_smile=ligand.get_original_smile(), 52 | ligand_number=ligand.get_ligand_number(), 53 | enumeration=get_next_enumeration_number_for_ligand(new_ligands_list, 54 | ligand.get_ligand_number()), 55 | molecule=None, 56 | mol_type=None, 57 | name=ligand.get_name())) 58 | return new_ligands_list 59 | -------------------------------------------------------------------------------- /dockstream/core/RDkit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/core/RDkit/__init__.py -------------------------------------------------------------------------------- /dockstream/core/Schrodinger/Glide_result_parser.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from dockstream.core.result_parser import ResultParser 3 | 4 | from dockstream.utils.enums.Schrodinger_enums import SchrodingerOutputEnum 5 | 6 | 7 | class GlideResultParser(ResultParser): 8 | """Class that loads, parses and analyzes the output of a "Glide" docking run, including poses and scores.""" 9 | def __init__(self, ligands: list): 10 | super().__init__(ligands=ligands) 11 | 12 | self._df_results = self._construct_dataframe() 13 | 14 | def _construct_dataframe(self) -> pd.DataFrame: 15 | def func_get_score(conformer): 16 | _ROE = SchrodingerOutputEnum() 17 | return float(conformer.GetProp(_ROE.GLIDE_DOCKING_SCORE)) 18 | 19 | return super()._construct_dataframe_with_funcobject(func_get_score) 20 | -------------------------------------------------------------------------------- /dockstream/core/Schrodinger/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/core/Schrodinger/__init__.py -------------------------------------------------------------------------------- /dockstream/core/TautEnum/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/core/TautEnum/__init__.py -------------------------------------------------------------------------------- /dockstream/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/core/__init__.py -------------------------------------------------------------------------------- /dockstream/core/factories/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/core/factories/__init__.py -------------------------------------------------------------------------------- /dockstream/core/factories/transformator_factory.py: -------------------------------------------------------------------------------- 1 | from dockstream.loggers.ligand_preparation_logger import LigandPreparationLogger 2 | from dockstream.utils.enums.logging_enums import LoggingConfigEnum 3 | from dockstream.core.OpenEye.OpenEye_transformator import OpenEyeTransformator 4 | from dockstream.utils.enums.transformations_enums import TransformationEnum 5 | 6 | 7 | class TransformatorFactory: 8 | """Returns a list of transformators.""" 9 | 10 | def __init__(self, conf): 11 | self._TE = TransformationEnum() 12 | self._LE = LoggingConfigEnum() 13 | self._logger = LigandPreparationLogger() 14 | self._conf = conf 15 | 16 | def get_transformators(self) -> list: 17 | transformators = [] 18 | for curTransConf in self._conf[self._TE.TRANSFORMATIONS]: 19 | if curTransConf[self._TE.TRANSFORMATION_BACKEND] == self._TE.TRANSFORMATION_BACKEND_OPENEYE: 20 | transformators.append(OpenEyeTransformator(curTransConf)) 21 | else: 22 | self._logger.log(f"", self._LE.DEBUG) 23 | 24 | return transformators 25 | -------------------------------------------------------------------------------- /dockstream/core/input_model.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional, Union 2 | 3 | from pydantic import BaseModel 4 | 5 | from dockstream.core.AutodockVina.AutodockVina_docker import AutodockVina 6 | from dockstream.core.Corina.Corina_ligand_preparator import CorinaLigandPreparator 7 | from dockstream.core.Gold.Gold_docker import Gold 8 | from dockstream.core.OpenEye.OpenEye_docker import OpenEye 9 | from dockstream.core.OpenEye.OpenEye_ligand_preparator import OpenEyeLigandPreparator 10 | from dockstream.core.OpenEyeHybrid.OpenEyeHybrid_docker import OpenEyeHybrid 11 | from dockstream.core.RDkit.RDkit_ligand_preparator import RDkitLigandPreparator 12 | from dockstream.core.Schrodinger.Glide_docker import Glide 13 | from dockstream.core.Schrodinger.Ligprep_ligand_preparator import LigprepLigandPreparator 14 | from dockstream.core.rDock.rDock_docker import rDock 15 | 16 | 17 | class EnvVariable(BaseModel): 18 | key: str 19 | value: str 20 | 21 | 22 | class Environment(BaseModel): 23 | export: Optional[List[EnvVariable]] 24 | 25 | 26 | class Logging(BaseModel): 27 | logfile: str 28 | 29 | 30 | class Header(BaseModel): 31 | environment: Optional[Environment] 32 | logging: Logging 33 | 34 | 35 | AnyLigandPreparator = Union[ 36 | # CorinaLigandPreparator, 37 | LigprepLigandPreparator, 38 | # OpenEyeLigandPreparator, 39 | # RDkitLigandPreparator, 40 | ] 41 | 42 | 43 | class LigandPreparation(BaseModel): 44 | """Ligand preparation: Specify embedding pool/ligand preparator.""" 45 | embedding_pools: Union[AnyLigandPreparator, List[AnyLigandPreparator]] 46 | 47 | 48 | AnyDocker = Union[ 49 | # AutodockVina, 50 | Glide, 51 | # Gold, 52 | # OpenEye, 53 | # OpenEyeHybrid, 54 | # rDock, 55 | ] 56 | 57 | 58 | class DockingInput(BaseModel): 59 | """Docking input. 60 | 61 | Consists of two big parts: ligand preparation and docking runs/backend. 62 | """ 63 | 64 | header: Header 65 | ligand_preparation: LigandPreparation 66 | docking_runs: Union[AnyDocker, Optional[List[AnyDocker]]] 67 | 68 | 69 | class AzdockInput(BaseModel): 70 | """Welcome to AZDock.""" 71 | docking: DockingInput 72 | -------------------------------------------------------------------------------- /dockstream/core/ligand/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/core/ligand/__init__.py -------------------------------------------------------------------------------- /dockstream/core/pdb_preparator.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | from pdbfixer import PDBFixer 3 | from openmm.vec3 import Vec3 4 | from openmm.app import PDBFile 5 | 6 | from dockstream.loggers.target_preparation_logger import TargetPreparationLogger 7 | from dockstream.utils.dockstream_exceptions import TargetPreparationFailed 8 | 9 | from dockstream.containers.target_preparation_container import TargetPreparationContainer 10 | from dockstream.utils.enums.target_preparation_enum import TargetPreparationEnum 11 | from dockstream.utils.enums.logging_enums import LoggingConfigEnum 12 | 13 | 14 | class PDBPreparator: 15 | """Wrapper class for "PDBFixer" functionality.""" 16 | 17 | def __init__(self, conf: TargetPreparationContainer): 18 | self._TE = TargetPreparationEnum() 19 | self._TL = LoggingConfigEnum() 20 | self._logger = TargetPreparationLogger() 21 | self._config = conf 22 | 23 | def fix_pdb(self, input_pdb_file, output_pdb_file): 24 | """Function that loads a PDB file and writes a fixed version to another PDB file.""" 25 | 26 | if self._TE.FIX not in self._config[self._TE.TARGETPREP].keys(): 27 | raise TargetPreparationFailed("Cannot fix target, if respective configuration block is missing.") 28 | 29 | paras = self._config[self._TE.TARGETPREP][self._TE.FIX] 30 | 31 | # load the target from a PDB file (generated temporarily in the child classes) 32 | fixer = PDBFixer(filename=input_pdb_file) 33 | self._logger.log(f"Initialized PDBFixer.", self._TL.DEBUG) 34 | 35 | # perform fixes specified in the configuration 36 | fixer.findMissingResidues() 37 | fixer.findNonstandardResidues() 38 | if paras[self._TE.FIX_STANDARDIZE]: 39 | fixer.replaceNonstandardResidues() 40 | self._logger.log(f"Replaced {len(fixer.nonstandardResidues)} non-standard residues.", self._TL.DEBUG) 41 | if paras[self._TE.FIX_REMOVEHETEROGENS]: 42 | fixer.removeHeterogens(keepWater=True) 43 | self._logger.log("Removed heterogens.", self._TL.DEBUG) 44 | if paras[self._TE.FIX_MISSINGHEAVYATOMS]: 45 | fixer.findMissingAtoms() 46 | fixer.addMissingAtoms() 47 | self._logger.log(f"Added {len(fixer.missingAtoms)} missing atoms.", self._TL.DEBUG) 48 | if paras[self._TE.FIX_MISSINGHYDROGENS]: 49 | fixer.addMissingHydrogens(pH=7.0) 50 | self._logger.log("Added missing hydrogens.", self._TL.DEBUG) 51 | if paras[self._TE.FIX_ADDWATERBOX]: 52 | # one could use the crystallographic unit cell, but that might be missing from the HEADER so go for a cubic 53 | # cell with some distance instead 54 | maxSize = max(max((pos[i] for pos in fixer.positions)) - 55 | min((pos[i] for pos in fixer.positions)) for i in range(3)) 56 | boxSize = maxSize * Vec3(1, 1, 1) 57 | fixer.addSolvent(boxSize) 58 | self._logger.log("Added water box.", self._TL.DEBUG) 59 | 60 | # write out the fixed target as another PDB file 61 | with warnings.catch_warnings(): 62 | warnings.simplefilter("ignore") 63 | PDBFile.writeFile(fixer.topology, fixer.positions, open(output_pdb_file, 'w')) 64 | -------------------------------------------------------------------------------- /dockstream/core/rDock/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/core/rDock/__init__.py -------------------------------------------------------------------------------- /dockstream/core/rDock/rDock_result_parser.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from dockstream.core.result_parser import ResultParser 3 | 4 | from dockstream.utils.enums.rDock_enums import rDockRbdockOutputEnum, rDockResultKeywordsEnum 5 | 6 | 7 | class rDockResultParser(ResultParser): 8 | """Class that loads, parses and analyzes the output of an "rDock" docking run, including poses and scores.""" 9 | def __init__(self, ligands): 10 | super().__init__(ligands=ligands) 11 | self._ROE = rDockRbdockOutputEnum() 12 | self._RK = rDockResultKeywordsEnum() 13 | 14 | self._df_results = self._construct_dataframe() 15 | 16 | def _construct_dataframe(self) -> pd.DataFrame: 17 | def func_get_score(conformer): 18 | return float(conformer.GetProp(self._ROE.SCORE)) 19 | 20 | return super()._construct_dataframe_with_funcobject(func_get_score) 21 | -------------------------------------------------------------------------------- /dockstream/core/result_parser.py: -------------------------------------------------------------------------------- 1 | import abc 2 | import pandas as pd 3 | import warnings 4 | from copy import deepcopy 5 | from dockstream.core.ligand.ligand import Ligand 6 | 7 | from dockstream.utils.dockstream_exceptions import ResultParsingFailed 8 | 9 | from dockstream.loggers.docking_logger import DockingLogger 10 | from dockstream.utils.enums.logging_enums import LoggingConfigEnum 11 | from dockstream.utils.enums.docking_enum import ResultKeywordsEnum 12 | 13 | 14 | class ResultParser(metaclass=abc.ABCMeta): 15 | """Base class implementing the interface result parsing classes.""" 16 | 17 | def __init__(self, ligands): 18 | self._LE = LoggingConfigEnum() 19 | self._logger = DockingLogger() 20 | self._RK = ResultKeywordsEnum() 21 | 22 | self._ligands = ligands 23 | self._df_results = None 24 | 25 | def as_dataframe(self, aggregate=False): 26 | if aggregate: 27 | warnings.warn("For now, \"aggregate\" is not available.") 28 | if isinstance(aggregate, bool) and aggregate is False: 29 | return deepcopy(self._df_results) 30 | else: 31 | raise ResultParsingFailed("Parameter aggregate has an illegal value.") 32 | 33 | @staticmethod 34 | def _get_name(ligand: Ligand, conformer_index: int): 35 | """Function to make get either the name (for named molecules) or the identifier (plus the conformer) for the dataframe.""" 36 | if ligand.get_name() is None: 37 | return ligand.get_identifier() + ':' + str(conformer_index) 38 | else: 39 | return ligand.get_name() 40 | 41 | def _construct_dataframe_with_funcobject(self, func_get_score) -> pd.DataFrame: 42 | data_buffer = [] 43 | for ligand in self._ligands: 44 | best = True 45 | for conformer_index, conformer in enumerate(ligand.get_conformers()): 46 | name = self._get_name(ligand, conformer_index) 47 | row = [ligand.get_ligand_number(), 48 | ligand.get_enumeration(), 49 | conformer_index, 50 | name, 51 | func_get_score(conformer), 52 | ligand.get_smile(), 53 | best] 54 | best = False 55 | data_buffer.append(row) 56 | return pd.DataFrame(data_buffer, columns=[self._RK.DF_LIGAND_NUMBER, 57 | self._RK.DF_LIGAND_ENUMERATION, 58 | self._RK.DF_CONFORMER, 59 | self._RK.DF_LIGAND_NAME, 60 | self._RK.DF_SCORE, 61 | self._RK.DF_SMILES, 62 | self._RK.DF_LOWEST_CONFORMER]) 63 | -------------------------------------------------------------------------------- /dockstream/core/stereo_enumerator.py: -------------------------------------------------------------------------------- 1 | from abc import ABC 2 | 3 | from pydantic import BaseModel, PrivateAttr 4 | 5 | from dockstream.loggers.ligand_preparation_logger import LigandPreparationLogger 6 | from dockstream.utils.enums.logging_enums import LoggingConfigEnum 7 | from dockstream.utils.enums.stereo_enumeration_enums import StereoEnumerationEnum 8 | 9 | _LE = LoggingConfigEnum() 10 | _SE = StereoEnumerationEnum() 11 | 12 | 13 | class StereoEnumerator(ABC, BaseModel): 14 | _logger = PrivateAttr() 15 | 16 | class Config: 17 | underscore_attrs_are_private = True 18 | 19 | def __init__(self, **data): 20 | super().__init__(**data) 21 | self._logger = LigandPreparationLogger() 22 | 23 | def enumerate(self, ligands: list) -> list: 24 | raise NotImplementedError 25 | -------------------------------------------------------------------------------- /dockstream/core/target_preparator.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | from dockstream.containers.target_preparation_container import TargetPreparationContainer 4 | from dockstream.utils.enums.target_preparation_enum import TargetPreparationEnum 5 | 6 | from dockstream.loggers.target_preparation_logger import TargetPreparationLogger 7 | from dockstream.loggers.blank_logger import BlankLogger 8 | 9 | from dockstream.utils.enums.logging_enums import LoggingConfigEnum 10 | 11 | 12 | class TargetPreparator(metaclass=abc.ABCMeta): 13 | """Virtual base class implementing the interface for all specific target preparators and the general preparation 14 | of the docking target.""" 15 | 16 | def __init__(self, conf: TargetPreparationContainer, run_number=0): 17 | self._TE = TargetPreparationEnum() 18 | self._TL = LoggingConfigEnum() 19 | self._logger = TargetPreparationLogger() 20 | self._logger_blank = BlankLogger() 21 | self._config = conf 22 | self._target = None 23 | 24 | # store the specific parameters for this very run for easy access later; the others are ignored 25 | self._run_parameters = self._config[self._TE.TARGETPREP][self._TE.RUNS][run_number] 26 | 27 | def get_target(self): 28 | return self._target 29 | 30 | def specify_cavity(self): 31 | raise NotImplementedError("This method needs to be overwritten by child classes.") 32 | 33 | def write_target(self, path): 34 | raise NotImplementedError("This method needs to be overwritten by child classes.") 35 | -------------------------------------------------------------------------------- /dockstream/core/transformator.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | from dockstream.utils.dockstream_exceptions import LigandPreparationFailed 4 | 5 | from dockstream.loggers.ligand_preparation_logger import LigandPreparationLogger 6 | from dockstream.loggers.blank_logger import BlankLogger 7 | from dockstream.utils.enums.logging_enums import LoggingConfigEnum 8 | from dockstream.utils.enums.transformations_enums import TransformationEnum 9 | 10 | 11 | class Transformator(metaclass=abc.ABCMeta): 12 | """Base class implementing the interface for transformations applied to smiles before embedding.""" 13 | 14 | def __init__(self, conf): 15 | self._LE = LoggingConfigEnum() 16 | self._TE = TransformationEnum() 17 | self._logger = LigandPreparationLogger() 18 | self._logger_blank = BlankLogger() 19 | self._conf = conf 20 | 21 | # extract type specification 22 | self._backend = conf[self._TE.TRANSFORMATION_BACKEND] 23 | if self._backend not in [self._TE.TRANSFORMATION_BACKEND_OPENEYE]: 24 | self._logger.log(f"Transformation backend {self._backend} is unknown.", self._LE.ERROR) 25 | raise LigandPreparationFailed(f"Transformation backend {self._backend} is unknown.") 26 | 27 | # extract backend specification 28 | self._type = conf[self._TE.TRANSFORMATION_TYPE] 29 | if self._type == self._TE.TRANSFORMATION_TYPE_SMIRKS: 30 | self._smirk = conf[self._TE.TRANSFORMATION_SMIRKS] 31 | else: 32 | self._logger.log(f"Transformation type {self._type} is unknown.", self._LE.ERROR) 33 | raise LigandPreparationFailed(f"Transformation type {self._type} is unknown.") 34 | 35 | # treat fail action specification 36 | self._fail_action = conf[self._TE.TRANSFORMATION_FAIL_ACTION] 37 | if self._fail_action not in [self._TE.TRANSFORMATION_FAIL_ACTION_KEEP, 38 | self._TE.TRANSFORMATION_FAIL_ACTION_DISCARD]: 39 | self._logger.log(f"Fail action {self._fail_action} is unknown.", self._LE.ERROR) 40 | raise LigandPreparationFailed(f"Fail action {self._fail_action} is unknown.") 41 | 42 | def transform(self, ligands: list) -> list: 43 | raise NotImplementedError 44 | -------------------------------------------------------------------------------- /dockstream/loggers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/loggers/__init__.py -------------------------------------------------------------------------------- /dockstream/loggers/base_logger.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | from dockstream.utils.enums.logging_enums import LoggingConfigEnum 4 | 5 | 6 | class BaseLogger(ABC): 7 | def __init__(self): 8 | self._LE = LoggingConfigEnum() 9 | self._logger = self._initialize_logger() 10 | 11 | def log(self, message: str, level: str): 12 | if level == self._LE.DEBUG: 13 | self._logger.debug(message) 14 | elif level == self._LE.INFO: 15 | self._logger.info(message) 16 | elif level == self._LE.WARNING: 17 | self._logger.warning(message) 18 | elif level == self._LE.ERROR: 19 | self._logger.error(message) 20 | elif level == self._LE.EXCEPTION: 21 | self._logger.exception(message) 22 | else: 23 | raise ValueError("Logger level not supported.") 24 | 25 | @abstractmethod 26 | def _initialize_logger(self): 27 | raise NotImplementedError("Overwrite this method in child classes.") 28 | -------------------------------------------------------------------------------- /dockstream/loggers/blank_logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from dockstream.loggers.base_logger import BaseLogger 4 | 5 | 6 | class BlankLogger(BaseLogger): 7 | """This logger serves as a "verbatim" interface.""" 8 | def __init__(self): 9 | super().__init__() 10 | 11 | def _initialize_logger(self): 12 | logger = logging.getLogger(self._LE.LOGGER_BLANK) 13 | return logger 14 | -------------------------------------------------------------------------------- /dockstream/loggers/docking_logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from dockstream.loggers.base_logger import BaseLogger 4 | 5 | 6 | class DockingLogger(BaseLogger): 7 | def __init__(self): 8 | super().__init__() 9 | 10 | def _initialize_logger(self): 11 | logger = logging.getLogger(self._LE.LOGGER_DOCKING) 12 | return logger 13 | -------------------------------------------------------------------------------- /dockstream/loggers/interface_logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | #from torch.utils.tensorboard import SummaryWriter 3 | 4 | from dockstream.loggers.base_logger import BaseLogger 5 | #from utils.logging.tensorboard import add_mols 6 | 7 | 8 | class InterfaceLogger(BaseLogger): 9 | def __init__(self): 10 | super().__init__() 11 | #self._summary_writer = self._instantiate_summary_writer(configuration) 12 | 13 | def _initialize_logger(self): 14 | logger = logging.getLogger(self._LE.LOGGER_INTERFACE) 15 | return logger 16 | 17 | #def __del__(self): 18 | # self._summary_writer.close() 19 | 20 | #def _log_timestep(self, smiles: np.array, likelihoods: np.array): 21 | # fraction_valid_smiles = utils_general.fraction_valid_smiles(smiles) 22 | # fraction_unique_entries = self._get_unique_entires_fraction(likelihoods) 23 | # self._visualize_structures(smiles) 24 | # self._summary_writer.add_text('Data', f'Valid SMILES: {fraction_valid_smiles}% ' 25 | # f'Unique Mols: {fraction_unique_entries}% ') 26 | 27 | #def _visualize_structures(self, smiles): 28 | # list_of_labels, list_of_mols = self._count_unique_inchi_keys(smiles) 29 | # if len(list_of_mols) > 0: 30 | # add_mols(self._summary_writer, "Most Frequent Molecules", list_of_mols, self._rows, list_of_labels) 31 | 32 | #def _instantiate_summary_writer(self, configuration): 33 | # log_config = SamplingLoggerConfiguration(**configuration.logging) 34 | # return SummaryWriter(log_dir=log_config.logging_path) -------------------------------------------------------------------------------- /dockstream/loggers/ligand_preparation_logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from dockstream.loggers.base_logger import BaseLogger 4 | 5 | 6 | class LigandPreparationLogger(BaseLogger): 7 | def __init__(self): 8 | super().__init__() 9 | 10 | def _initialize_logger(self): 11 | logger = logging.getLogger(self._LE.LOGGER_LIGAND_PREPARATION) 12 | return logger 13 | -------------------------------------------------------------------------------- /dockstream/loggers/target_preparation_logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from dockstream.loggers.base_logger import BaseLogger 4 | 5 | 6 | class TargetPreparationLogger(BaseLogger): 7 | def __init__(self): 8 | super().__init__() 9 | 10 | def _initialize_logger(self): 11 | logger = logging.getLogger(self._LE.LOGGER_TARGET_PREPARATION) 12 | return logger 13 | -------------------------------------------------------------------------------- /dockstream/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/utils/__init__.py -------------------------------------------------------------------------------- /dockstream/utils/argparse_bool_extension.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | 4 | def str2bool(inp): 5 | if isinstance(inp, bool): 6 | return inp 7 | if inp.lower() in ("yes", "true", 't', 'y', '1'): 8 | return True 9 | elif inp.lower() in ("no", "false", 'f', 'n', '0'): 10 | return False 11 | else: 12 | raise argparse.ArgumentTypeError("Expected castable string or boolean value as input.") 13 | -------------------------------------------------------------------------------- /dockstream/utils/dockstream_exceptions.py: -------------------------------------------------------------------------------- 1 | 2 | class LigandPreparationFailed(Exception): 3 | pass 4 | 5 | 6 | class ConfigParsingFailed(Exception): 7 | pass 8 | 9 | 10 | class DockingRunFailed(Exception): 11 | pass 12 | 13 | 14 | class TargetPreparationFailed(Exception): 15 | pass 16 | 17 | 18 | class ResultParsingFailed(Exception): 19 | pass 20 | 21 | 22 | class TransformationFailed(Exception): 23 | pass 24 | 25 | 26 | def get_exception_message(e: Exception): 27 | if hasattr(e, "message"): 28 | return e.message 29 | else: 30 | return e 31 | -------------------------------------------------------------------------------- /dockstream/utils/entry_point_functions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/utils/entry_point_functions/__init__.py -------------------------------------------------------------------------------- /dockstream/utils/entry_point_functions/embedding.py: -------------------------------------------------------------------------------- 1 | from dockstream.core.ligand.ligand_input_parser import LigandInputParser 2 | 3 | from dockstream.utils.dockstream_exceptions import * 4 | 5 | from dockstream.core.RDkit.RDkit_ligand_preparator import RDkitLigandPreparator 6 | from dockstream.core.OpenEye.OpenEye_ligand_preparator import OpenEyeLigandPreparator 7 | from dockstream.core.Corina.Corina_ligand_preparator import CorinaLigandPreparator 8 | from dockstream.core.Schrodinger.Ligprep_ligand_preparator import LigprepLigandPreparator 9 | from dockstream.core.OpenEyeHybrid.Omega_ligand_preparator import OmegaLigandPreparator 10 | 11 | from dockstream.utils.enums.docking_enum import DockingConfigurationEnum 12 | from dockstream.utils.enums.ligand_preparation_enum import LigandPreparationEnum 13 | from dockstream.utils.enums.logging_enums import LoggingConfigEnum 14 | 15 | 16 | def embed_ligands(smiles, pool_number, pool, logger, ligand_number_start=0): 17 | # enums 18 | _LE = LoggingConfigEnum() 19 | _LP = LigandPreparationEnum() 20 | _DE = DockingConfigurationEnum() 21 | 22 | # 1) load and parse the input, whether from command-line or from the configuration 23 | # note, that if "args.smiles" is not None, those smiles will be use irrespective of the configuration 24 | lig_inp_parser = LigandInputParser(smiles=smiles, 25 | ligand_number_start=ligand_number_start, 26 | **pool) 27 | list_ligands = lig_inp_parser.get_ligands() 28 | if len(list_ligands) == 0: 29 | raise LigandPreparationFailed("No smiles found in input.") 30 | logger.log(f"Loaded {len(list_ligands)} molecules.", _LE.DEBUG) 31 | 32 | # 2) do the embedding 33 | if pool[_LP.TYPE] == _LP.TYPE_RDKIT: 34 | prep = RDkitLigandPreparator(ligands=list_ligands, pool_number=pool_number, **pool) 35 | elif pool[_LP.TYPE] == _LP.TYPE_OPENEYE: 36 | prep = OpenEyeLigandPreparator(ligands=list_ligands, pool_number=pool_number, **pool) 37 | elif pool[_LP.TYPE] == _LP.TYPE_CORINA: 38 | prep = CorinaLigandPreparator(ligands=list_ligands, pool_number=pool_number, **pool) 39 | elif pool[_LP.TYPE] == _LP.TYPE_LIGPREP: 40 | prep = LigprepLigandPreparator(ligands=list_ligands, pool_number=pool_number, **pool) 41 | elif pool[_LP.TYPE] == _LP.TYPE_OMEGA: 42 | prep = OmegaLigandPreparator(ligands=list_ligands, pool_number=pool_number, **pool) 43 | else: 44 | raise LigandPreparationFailed("Type of pool is unknown.") 45 | 46 | # generate 3D coordinates (embed), if not using SDF input 47 | if _LP.INPUT_TYPE not in pool[_LP.INPUT].keys() or pool[_LP.INPUT][_LP.INPUT_TYPE].upper() != _LP.INPUT_TYPE_SDF: 48 | prep.generate3Dcoordinates() 49 | else: 50 | logger.log(f"As input is SDF, coordinate generation is skipped.", _LE.INFO) 51 | 52 | # 3) (optional) do alignment 53 | if _LP.ALIGN in pool.keys(): 54 | prep.align_ligands() 55 | 56 | # 4) (optional) write the molecules to the disk 57 | if _LP.OUTPUT in pool.keys(): 58 | prep.write_ligands(path=pool[_LP.OUTPUT][_LP.OUTPUT_CONFORMERPATH], 59 | format=pool[_LP.OUTPUT][_LP.OUTPUT_FORMAT]) 60 | 61 | # 5) save the ligands in the respective pool 62 | # note, that a "pool" represents an embedded collection of molecules 63 | return prep 64 | -------------------------------------------------------------------------------- /dockstream/utils/entry_point_functions/header.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import logging.config as logging_config 4 | from dockstream.loggers.interface_logger import InterfaceLogger 5 | 6 | from dockstream.utils.files_paths import dict_from_json_file 7 | 8 | from dockstream.utils.enums.logging_enums import LoggingConfigEnum 9 | from dockstream.utils.general_utils import * 10 | 11 | _LE = LoggingConfigEnum() 12 | 13 | 14 | def initialize_logging(config, task, _task_enum, log_conf_path): 15 | if in_keys(config, [task, _task_enum.HEADER]): 16 | log_conf_dict = dict_from_json_file(log_conf_path) 17 | if in_keys(config, [task, _task_enum.HEADER, _task_enum.LOGGING]): 18 | if in_keys(config, [task, _task_enum.HEADER, _task_enum.LOGGING, _task_enum.LOGGING_LOGFILE]): 19 | try: 20 | log_conf_dict["handlers"]["file_handler"]["filename"] = config[task][_task_enum.HEADER][_task_enum.LOGGING][_task_enum.LOGGING_LOGFILE] 21 | log_conf_dict["handlers"]["file_handler_blank"]["filename"] = config[task][_task_enum.HEADER][_task_enum.LOGGING][_task_enum.LOGGING_LOGFILE] 22 | except KeyError: 23 | pass 24 | logging_config.dictConfig(log_conf_dict) 25 | else: 26 | logging_config.dictConfig(dict_from_json_file(log_conf_path)) 27 | logger = InterfaceLogger() 28 | logger.log(f"DockStream version used: {parse_setuppy()['version']}", _LE.INFO) 29 | return logger 30 | 31 | 32 | def set_environment(config, task, _task_enum, logger): 33 | if in_keys(config, [task, _task_enum.HEADER]): 34 | if in_keys(config, [task, _task_enum.HEADER, _task_enum.ENVIRONMENT]): 35 | if in_keys(config, [task, _task_enum.HEADER, _task_enum.ENVIRONMENT, _task_enum.ENVIRONMENT_EXPORT]): 36 | exp_vars = config[task][_task_enum.HEADER][_task_enum.ENVIRONMENT][_task_enum.ENVIRONMENT_EXPORT] 37 | for export in exp_vars: 38 | os.environ[export[_task_enum.ENVIRONMENT_EXPORT_KEY]] = export[_task_enum.ENVIRONMENT_EXPORT_VALUE] 39 | logger.log(f"Added environment variable {export[_task_enum.ENVIRONMENT_EXPORT_KEY]}: {export[_task_enum.ENVIRONMENT_EXPORT_VALUE]}.", _LE.DEBUG) 40 | -------------------------------------------------------------------------------- /dockstream/utils/entry_point_functions/write_out.py: -------------------------------------------------------------------------------- 1 | from dockstream.utils.enums.docking_enum import DockingConfigurationEnum, ResultKeywordsEnum 2 | from dockstream.utils.enums.ligand_preparation_enum import LigandPreparationEnum 3 | from dockstream.utils.enums.logging_enums import LoggingConfigEnum 4 | 5 | from dockstream.utils.general_utils import * 6 | 7 | 8 | def handle_poses_writeout(docking_run, docker, output_prefix): 9 | _LE = LoggingConfigEnum() 10 | _LP = LigandPreparationEnum() 11 | _DE = DockingConfigurationEnum() 12 | 13 | if in_keys(docking_run, [_DE.OUTPUT, _DE.OUTPUT_POSES]): 14 | if in_keys(docking_run, [_DE.OUTPUT, _DE.OUTPUT_POSES, _DE.OUTPUT_POSES_PATH]): 15 | poses_path = docking_run[_DE.OUTPUT][_DE.OUTPUT_POSES][_DE.OUTPUT_POSES_PATH] 16 | poses_path = docker.apply_prefix_to_filename(poses_path, output_prefix) 17 | 18 | # if the overwrite flag is set and the output file exists already, append number to basename 19 | if nested_get(docking_run, [_DE.OUTPUT, 20 | _DE.OUTPUT_POSES, 21 | _DE.OUTPUT_POSES_OVERWRITE], 22 | default=False): 23 | poses_path = docker.update_path_to_unused(path=poses_path) 24 | 25 | mode = nested_get(docking_run, [_DE.OUTPUT, _DE.OUTPUT_POSES, _DE.OUTPUT_MODE], 26 | default=_DE.OUTPUT_MODE_ALL) 27 | docker.write_docked_ligands(path=poses_path, mode=mode) 28 | 29 | 30 | def handle_scores_writeout(docking_run, docker, output_prefix): 31 | _LE = LoggingConfigEnum() 32 | _LP = LigandPreparationEnum() 33 | _DE = DockingConfigurationEnum() 34 | 35 | if in_keys(docking_run, [_DE.OUTPUT, _DE.OUTPUT_SCORES]): 36 | if in_keys(docking_run, [_DE.OUTPUT, _DE.OUTPUT_SCORES, _DE.OUTPUT_SCORES_PATH]): 37 | scores_path = docking_run[_DE.OUTPUT][_DE.OUTPUT_SCORES][_DE.OUTPUT_SCORES_PATH] 38 | scores_path = docker.apply_prefix_to_filename(scores_path, output_prefix) 39 | 40 | # if the overwrite flag is set and the output file exists already, append number to basename 41 | if nested_get(docking_run, [_DE.OUTPUT, _DE.OUTPUT_SCORES, _DE.OUTPUT_SCORES_OVERWRITE], 42 | default=False): 43 | scores_path = docker.update_path_to_unused(path=scores_path) 44 | 45 | mode = nested_get(docking_run, [_DE.OUTPUT, _DE.OUTPUT_SCORES, _DE.OUTPUT_MODE], 46 | default=_DE.OUTPUT_MODE_ALL) 47 | docker.write_result(path=scores_path, mode=mode) 48 | 49 | 50 | def handle_score_printing(print_scores: bool, print_all: bool, docker, logger): 51 | _LE = LoggingConfigEnum() 52 | _LP = LigandPreparationEnum() 53 | _DE = DockingConfigurationEnum() 54 | 55 | if print_scores: 56 | _RK = ResultKeywordsEnum() 57 | scores = docker.get_scores(best_only=not print_all) 58 | for score in scores: 59 | print(score, end="\n") 60 | logger.log(f"Printed {len(scores)} scores to console (print_all set to {print_all}).", _LE.DEBUG) -------------------------------------------------------------------------------- /dockstream/utils/enums/Corina_enums.py: -------------------------------------------------------------------------------- 1 | from dockstream.utils.enums.ligand_preparation_enum import LigandPreparationEnum 2 | 3 | 4 | class CorinaLigandPreparationEnum(LigandPreparationEnum): 5 | 6 | OUTPUT_FORMAT_MAE = "MAE" 7 | D_OPTIONS = "d_options" 8 | ENUMERATE_STEREO = "enumerate_stereo" 9 | 10 | # try to find the internal value and return 11 | def __getattr__(self, name): 12 | if name in self: 13 | return name 14 | raise AttributeError 15 | 16 | # prohibit any attempt to set any values 17 | def __setattr__(self, key, value): 18 | raise ValueError("No changes allowed.") 19 | 20 | 21 | class CorinaOutputEnum: 22 | """This "Enum" serves to store all keywords that are used by the "corina" executable.""" 23 | 24 | # try to find the internal value and return 25 | def __getattr__(self, name): 26 | if name in self: 27 | return name 28 | raise AttributeError 29 | 30 | # prohibit any attempt to set any values 31 | def __setattr__(self, key, value): 32 | raise ValueError("No changes allowed.") 33 | 34 | 35 | class CorinaExecutablesEnum: 36 | """This "Enum" serves to store all the executables (and parameters) as strings available in the "Corina" backend.""" 37 | 38 | # executable "corina" + parameters 39 | # --------- 40 | CORINA = "corina" 41 | CORINA_I = "-i" 42 | CORINA_T_SMILES = "t=smiles" 43 | CORINA_O = "-o" 44 | CORINA_T_SDF = "t=sdf" 45 | CORINA_D = "-d" 46 | CORINA_HELP = "-h" 47 | CORINA_HELP_IDENTIFICATION_STRING = "3D-structure generator" # if string found in "stderr" of result, "corina" 48 | # is available 49 | CORINA_T = "-t" # trace level (results in "corina.trc" file) 50 | CORINA_T_DISABLED = "n" 51 | 52 | # try to find the internal value and return 53 | def __getattr__(self, name): 54 | if name in self: 55 | return name 56 | raise AttributeError 57 | 58 | # prohibit any attempt to set any values 59 | def __setattr__(self, key, value): 60 | raise ValueError("No changes allowed.") 61 | -------------------------------------------------------------------------------- /dockstream/utils/enums/OpenBabel_enums.py: -------------------------------------------------------------------------------- 1 | 2 | class OpenBabelOutputEnum: 3 | 4 | # try to find the internal value and return 5 | def __getattr__(self, name): 6 | if name in self: 7 | return name 8 | raise AttributeError 9 | 10 | # prohibit any attempt to set any values 11 | def __setattr__(self, key, value): 12 | raise ValueError("No changes allowed.") 13 | 14 | 15 | class OpenBabelExecutablesEnum: 16 | 17 | # executable "obabel" + parameters 18 | # --------- 19 | OBABEL = "obabel" 20 | OBABEL_IDENTIFICATION_STRING = "-O" 21 | OBABLE_INPUTFORMAT_PDBQT = "-ipdbqt" # sets the input format to "PDBQT" (output of "AutoDock Vina") 22 | OBABEL_P = "-p" # sets the value (e.g. "-p 7.4") for protonation 23 | # note, that this overwrites "--addpolarh", which is thus not used 24 | OBABEL_O = "-O" # specifies the output path (directly pasted afterwards, e.g. "-Omypath.pdb") 25 | OBABEL_OUTPUT_FORMAT_PDBQT = "-opdbqt" # sets the output format to "PDBQT" (input for "AutoDock Vina") 26 | OBABEL_OUTPUT_FORMAT_SDF = "-osdf" # sets the output format to "SDF" 27 | OBABEL_X = "-x" # specifies generation options 28 | OBABEL_X_R = 'r' # one of the 'X' options ("-x"), which disables the tree construction of the receptor (makes it static), directly pasted together: e.g. "-xr" 29 | OBABEL_PARTIALCHARGE = "--partialcharge" # sets the partial charge generation method (execute "obabel -L charges" to see list of available methods) 30 | OBABEL_PARTIALCHARGE_GASTEIGER = "gasteiger" # one method to compute the partial charges, used as: "--partialcharge gasteiger" 31 | 32 | # try to find the internal value and return 33 | def __getattr__(self, name): 34 | if name in self: 35 | return name 36 | raise AttributeError 37 | 38 | # prohibit any attempt to set any values 39 | def __setattr__(self, key, value): 40 | raise ValueError("No changes allowed.") 41 | -------------------------------------------------------------------------------- /dockstream/utils/enums/OpenEye_enums.py: -------------------------------------------------------------------------------- 1 | from dockstream.utils.enums.target_preparation_enum import TargetPreparationEnum 2 | from dockstream.utils.enums.ligand_preparation_enum import LigandPreparationEnum 3 | from dockstream.utils.enums.docking_enum import DockingConfigurationEnum, ResultKeywordsEnum 4 | 5 | 6 | class OpenEyeLigandPreparationEnum(LigandPreparationEnum): 7 | 8 | # align using OpenEye's template version, which is set at the receptor building stage 9 | ALIGN_MODE_OPENEYERECEPTOR = "OpenEye_receptor" 10 | 11 | # try to find the internal value and return 12 | def __getattr__(self, name): 13 | if name in self: 14 | return name 15 | raise AttributeError 16 | 17 | # prohibit any attempt to set any values 18 | def __setattr__(self, key, value): 19 | raise ValueError("No changes allowed.") 20 | 21 | 22 | class OpenEyeTargetPreparationEnum(TargetPreparationEnum): 23 | 24 | OUTPUT_RECEPTORPATH = "receptor_path" 25 | 26 | CAVITY_METHOD_BOX = "box" 27 | CAVITY_BOX_LIMITS = "limits" 28 | CAVITY_METHOD_HINT = "hint" 29 | CAVITY_HINT_COORDINATES = "coordinates" 30 | 31 | 32 | # try to find the internal value and return 33 | def __getattr__(self, name): 34 | if name in self: 35 | return name 36 | raise AttributeError 37 | 38 | # prohibit any attempt to set any values 39 | def __setattr__(self, key, value): 40 | raise ValueError("No changes allowed.") 41 | 42 | 43 | class OpenEyeDockingConfigurationEnum(DockingConfigurationEnum): 44 | 45 | RECEPTOR_PATHS = "receptor_paths" 46 | 47 | # scoring functions 48 | # --------- 49 | SCORING = "scoring" 50 | SCORING_INVALID_VALUE = 16777215 51 | # McGann2003: shape-based scoring function that favours poses that complement the active site well, ignoring any 52 | # chemical interactions; good choice to ensure shape-complementarity 53 | SCORING_SHAPEGAUSS = "Shapegauss" 54 | # Verkhivker2002: Piecewise Linear Potential uses both shape and hydrogen bond complementarity; in the implementation 55 | # used, it also includes metal-based interactions 56 | SCORING_PLP = "PLP" 57 | # Eldridge1997: includes lipophilic, H-bonds, metals, clashes, rotatable bonds 58 | SCORING_CHEMSCORE = "Chemscore" 59 | # the Chemgauss-scoring functions use Gaussian smoothed potentials to measure complementarity; includes shape, 60 | # H-bonds between ligand and protein, H-bonds with implicit solvent and metal interactions; version 4 is an 61 | # improvement in terms of H-bonding 62 | SCORING_CHEMGAUSS3 = "Chemgauss3" 63 | SCORING_CHEMGAUSS4 = "Chemgauss4" 64 | SCORING_HYBRID1 = "Hybrid1" 65 | SCORING_HYBRID2 = "Hybrid2" 66 | 67 | # resolution (specifies search resolution during exhaustive search and local optimization as well as the number 68 | # of poses passed from the exhaustive step to the optimization step 69 | # --------- 70 | RESOLUTION = "resolution" 71 | RESOLUTION_INVALID_VALUE = 16777215 72 | RESOLUTION_HIGH = "High" # 1000 poses passed 73 | RESOLUTION_STANDARD = "Standard" # 100 poses passed 74 | RESOLUTION_LOW = "Low" # 100 poses passed 75 | 76 | # try to find the internal value and return 77 | def __getattr__(self, name): 78 | if name in self: 79 | return name 80 | raise AttributeError 81 | 82 | # prohibit any attempt to set any values 83 | def __setattr__(self, key, value): 84 | raise ValueError("No changes allowed.") 85 | 86 | 87 | class OpenEyeResultKeywordsEnum(ResultKeywordsEnum): 88 | """This "Enum" serves to store all keywords for "OpenEye" result dictionaries.""" 89 | 90 | 91 | 92 | # try to find the internal value and return 93 | def __getattr__(self, name): 94 | if name in self: 95 | return name 96 | raise AttributeError 97 | 98 | # prohibit any attempt to set any values 99 | def __setattr__(self, key, value): 100 | raise ValueError("No changes allowed.") 101 | -------------------------------------------------------------------------------- /dockstream/utils/enums/RDkit_enums.py: -------------------------------------------------------------------------------- 1 | from dockstream.utils.enums.ligand_preparation_enum import LigandPreparationEnum 2 | 3 | 4 | class RDkitLigandPreparationEnum(LigandPreparationEnum): 5 | 6 | TAG_RDOCK_TETHERED_ATOMS = "TETHERED ATOMS" 7 | 8 | # 3D coordinates generation 9 | # --------- 10 | EP_PARAMS_COORDGEN = "coordinate_generation" 11 | EP_PARAMS_COORDGEN_METHOD = "method" 12 | EP_PARAMS_COORDGEN_UFF = "UFF" 13 | EP_PARAMS_COORDGEN_UFF_MAXITERS = "maximum_iterations" 14 | 15 | # tie molecules to a reference during docking 16 | ALIGN_TETHERING = "tethering" 17 | 18 | # keywords for molecule tags 19 | # --------- 20 | TAG_ALIGNED_ATOMS = "ALIGNED ATOMS" 21 | TAG_ALIGNED_RMSD = "ALIGNED RMSD" 22 | TAG_ALIGNED_REFERENCE = "ALIGNED REFERENCE" 23 | TAG_ALIGNED_ATOMS_RATIO = "ALIGNED ATOMS RATIO" 24 | 25 | PROTONATE = "protonate" 26 | 27 | # try to find the internal value and return 28 | def __getattr__(self, name): 29 | if name in self: 30 | return name 31 | raise AttributeError 32 | 33 | # prohibit any attempt to set any values 34 | def __setattr__(self, key, value): 35 | raise ValueError("No changes allowed.") -------------------------------------------------------------------------------- /dockstream/utils/enums/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/utils/enums/__init__.py -------------------------------------------------------------------------------- /dockstream/utils/enums/analysis_enums.py: -------------------------------------------------------------------------------- 1 | 2 | class AnalysisConfigurationEnum: 3 | 4 | ANALYSIS = "analysis" 5 | 6 | # RMSD 7 | # --------- 8 | RMSD = "rmsd" 9 | RMSD_DATA = "data" 10 | RMSD_DATA_MOLECULES_PATH = "molecules_path" 11 | RMSD_DATA_NAME = "name" 12 | RMSD_OUTPUT = "output" 13 | RMSD_OUTPUT_SUMMARY_PATH = "summary_path" 14 | RMSD_OUTPUT_DETAILS_PATH = "details_path" 15 | RMSD_OUTPUT_HEATMAP_PATH = "heatmap_path" 16 | 17 | # try to find the internal value and return 18 | def __getattr__(self, name): 19 | if name in self: 20 | return name 21 | raise AttributeError 22 | 23 | # prohibit any attempt to set any values 24 | def __setattr__(self, key, value): 25 | raise ValueError("No changes allowed.") 26 | 27 | 28 | class AnalysisInternalEnum: 29 | 30 | DATA_NAME = "name" 31 | MOLECULES = "molecules" 32 | FIRST_SET = "first_set" 33 | SECOND_SET = "second_set" 34 | LIST_RMSD_VALUES = "list_rmsd_values" 35 | MEAN_RMSD_VALUES = "mean_rmsd_values" 36 | SD_RMSD_VALUES = "sd_rmsd_values" 37 | 38 | # try to find the internal value and return 39 | def __getattr__(self, name): 40 | if name in self: 41 | return name 42 | raise AttributeError 43 | 44 | # prohibit any attempt to set any values 45 | def __setattr__(self, key, value): 46 | raise ValueError("No changes allowed.") 47 | 48 | 49 | class AnalysisEnum: 50 | """this "Enum" defines all the strings required in the analysis script.""" 51 | 52 | # Input Docking Data 53 | # -------------------------------------- 54 | 55 | INPUT_DOCKING_DATA = "input_docking_data" 56 | DATA_PATH = "data_path" 57 | LIGAND_NUMBER = "ligand_number" 58 | DATA_METRIC = "data_metric" 59 | MAX_DATA_METRIC_BEST = "max_data_metric_best" 60 | DATA_THRESHOLDS = "data_thresholds" 61 | 62 | # Input Experimental Data 63 | # -------------------------------------- 64 | 65 | INPUT_EXP_DATA = "input_exp_data" 66 | EXP_DATA_PATH = "exp_data_path" 67 | EXP_METRIC = "exp_metric" 68 | COMPARISON_SCORE = "comparison_score" 69 | MAX_EXP_METRIC_BEST = "max_exp_metric_best" 70 | EXP_THRESHOLDS = "exp_thresholds" 71 | 72 | # Input Binary Actives/Inactives Data 73 | # --------------------------------------- 74 | 75 | INPUT_ENRICHMENT_DATA = "input_enrichment_data" 76 | DATA_PATH_ACTIVES = "data_path_actives" 77 | DATA_PATH_INACTIVES = "data_path_inactives" 78 | ACTIVES_DATA_METRIC = "actives_data_metric" 79 | INACTIVES_DATA_METRIC = "inactives_data_metric" 80 | MAX_METRIC_BEST = "max_metric_best" 81 | ACTIVES = "Actives" 82 | INACTIVES = "Inactives" 83 | 84 | # Plots 85 | # --------------------------------------- 86 | 87 | PLOT_SETTINGS = "plot_settings" 88 | ENRICHMENT_ANALYSIS = "enrichment_analysis" 89 | PROC_OVERLAY = "pROC_overlay" 90 | 91 | # Output Folder 92 | # --------------------------------------- 93 | 94 | OUTPUT = "output" 95 | OUTPUT_PATH = "output_path" 96 | 97 | # Histogram Plot Parameters 98 | # --------------------------------------- 99 | 100 | HIST_TWO_COLOURS = ['green', 'blue'] 101 | HIST_THREE_COLOURS = ['green', 'orange', 'blue'] 102 | HIST_FOUR_COLOURS = ['green', 'orange', 'blue', 'cyan'] 103 | 104 | -------------------------------------------------------------------------------- /dockstream/utils/enums/docking_enum.py: -------------------------------------------------------------------------------- 1 | 2 | class DockingConfigurationEnum: 3 | """This "Enum" serves to store all the strings used in parsing "DockStream" configurations.""" 4 | 5 | DOCKING = "docking" 6 | 7 | # header region 8 | # --------- 9 | HEADER = "header" 10 | ENVIRONMENT = "environment" 11 | ENVIRONMENT_EXPORT = "export" 12 | ENVIRONMENT_EXPORT_KEY = "key" 13 | ENVIRONMENT_EXPORT_VALUE = "value" 14 | LOGGING = "logging" 15 | LOGGING_VERBOSITY = "verbosity" 16 | LOGGING_LOGFILE = "logfile" 17 | 18 | DOCKING_RUNS = "docking_runs" 19 | 20 | RUN_ID = "run_id" 21 | INPUT_POOLS = "input_pools" 22 | PARAMS = "parameters" 23 | PARAMS_PREFIX_EXECUTION = "prefix_execution" 24 | PARAMS_BINARY_LOCATION = "binary_location" 25 | 26 | # parallelization 27 | # --------- 28 | PARALLELIZATION = "parallelization" 29 | PARALLELIZATION_NUMBER_CORES = "number_cores" 30 | PARALLELIZATION_MAXCOMPOUNDSPERSUBJOB = "max_compounds_per_subjob" 31 | 32 | # the different backend types 33 | # --------- 34 | BACKEND = "backend" 35 | BACKEND_RDOCK = "rDock" 36 | BACKEND_OPENEYE = "OpenEye" 37 | BACKEND_OPENEYEHYBRID = "Hybrid" 38 | BACKEND_AUTODOCKVINA = "AutoDockVina" 39 | BACKEND_GOLD = "Gold" 40 | BACKEND_GLIDE = "Glide" 41 | 42 | # structural alignment to reference 43 | # --------- 44 | ALIGN = "align" 45 | ALIGN_REFERENCE_PATHS = "reference_paths" 46 | ALIGN_MINIMUM_SUBSTRUCTURE_RATIO = "minimum_substructure_ratio" 47 | ALIGN_COMPLETE_RINGS_ONLY = "complete_rings_only" 48 | 49 | # what to do in cases, where no alignment can be made, define what to do 50 | ALIGN_FAIL_ACTION = "fail_action" 51 | ALIGN_FAIL_DISCARD = "discard" 52 | ALIGN_FAIL_KEEP = "keep" 53 | 54 | # output 55 | OUTPUT = "output" 56 | OUTPUT_POSES = "poses" 57 | OUTPUT_POSES_OVERWRITE = "overwrite" 58 | OUTPUT_POSES_PATH = "poses_path" 59 | OUTPUT_SCORES = "scores" 60 | OUTPUT_SCORES_OVERWRITE = "overwrite" 61 | OUTPUT_SCORES_PATH = "scores_path" 62 | OUTPUT_MODE = "mode" 63 | OUTPUT_MODE_ALL = "all" 64 | OUTPUT_MODE_BESTPERLIGAND = "best_per_ligand" 65 | OUTPUT_MODE_BESTPERENUMERATION = "best_per_enumeration" 66 | 67 | # number poses returned from docking (top X poses) 68 | NUMBER_POSES = "number_poses" 69 | 70 | # try to find the internal value and return 71 | def __getattr__(self, name): 72 | if name in self: 73 | return name 74 | raise AttributeError 75 | 76 | # prohibit any attempt to set any values 77 | def __setattr__(self, key, value): 78 | raise ValueError("No changes allowed.") 79 | 80 | 81 | class ResultKeywordsEnum: 82 | """This "Enum" serves to store all keywords for result dictionaries.""" 83 | 84 | # ResultParser::get_result() result dataframe 85 | # --------- 86 | DF_LIGAND_NAME = "name" 87 | DF_LIGAND_NAME_MOLECULE = "" 88 | DF_LIGAND_NAME_CONFORMER = "" 89 | DF_LIGAND_NUMBER = "ligand_number" 90 | DF_LIGAND_ENUMERATION = "enumeration" 91 | DF_CONFORMER = "conformer_number" 92 | DF_SCORE = "score" 93 | DF_SMILES = "smiles" 94 | DF_LOWEST_CONFORMER = "lowest_conformer" 95 | AGGREGATE_BEST = "best" 96 | AGGREGATE_AVERAGE = "average" 97 | 98 | # fixed values 99 | # --------- 100 | FIXED_VALUE_NA = "NA" 101 | 102 | # try to find the internal value and return 103 | def __getattr__(self, name): 104 | if name in self: 105 | return name 106 | raise AttributeError 107 | 108 | # prohibit any attempt to set any values 109 | def __setattr__(self, key, value): 110 | raise ValueError("No changes allowed.") 111 | -------------------------------------------------------------------------------- /dockstream/utils/enums/ligand_preparation_enum.py: -------------------------------------------------------------------------------- 1 | 2 | class LigandPreparationEnum: 3 | """This "Enum" serves to store all the strings used in parsing "DockStream" configurations concerning ligands.""" 4 | 5 | LIGAND_PREPARATION = "ligand_preparation" 6 | 7 | # the embedding (3D coordinate generation) 8 | EMBEDDING_POOLS = "embedding_pools" 9 | POOLID = "pool_id" 10 | MOLECULES = "molecules" 11 | PARAMS = "parameters" 12 | 13 | # input parameters 14 | INPUT = "input" 15 | INPUT_STANDARDIZE_SMILES = "standardize_smiles" 16 | INPUT_PATH = "input_path" 17 | INPUT_TYPE = "type" 18 | INPUT_TYPE_CONSOLE = "CONSOLE" 19 | INPUT_TYPE_LIST = "LIST" 20 | INPUT_TYPE_SMI = "SMI" 21 | INPUT_TYPE_CSV = "CSV" 22 | INPUT_TYPE_SDF = "SDF" 23 | PREFIX_EXECUTION = "prefix_execution" 24 | BINARY_LOCATION = "binary_location" 25 | INITIALIZATION_MODE = "initialization_mode" 26 | INITIALIZATION_MODE_ORDER = "order" 27 | INITIALIZATION_MODE_AZDOCK = "dockstream" 28 | 29 | # CSV input 30 | INPUT_CSV_DELIMITER = "delimiter" 31 | INPUT_CSV_DELIMITER_DEFAULT = ',' 32 | INPUT_CSV_COLUMNS = "columns" 33 | INPUT_CSV_COLNAME_SMILES = "smiles" 34 | INPUT_CSV_COLNAME_NAMES = "names" 35 | 36 | # SDF input 37 | INPUT_SDF_TAGS = "tags" 38 | INPUT_SDF_TAGNAME_NAMES = "names" 39 | 40 | # output parameters 41 | OUTPUT = "output" 42 | OUTPUT_CONFORMERPATH = "conformer_path" 43 | OUTPUT_FORMAT = "format" 44 | OUTPUT_FORMAT_SDF = "SDF" 45 | OUTPUT_FORMAT_MOL2 = "MOL2" 46 | 47 | # TautEnum can be used to prepare the smiles (input) 48 | # --------- 49 | USE_TAUT_ENUM = "use_taut_enum" 50 | TAUT_ENUM_PREFIX_EXECUTION = "prefix_execution" 51 | TAUT_ENUM_ENUMERATE_PROTONATION = "enumerate_protonation" 52 | TAUT_ENUM_BINARY_LOCATION = "binary_location" 53 | 54 | # the different types of embedding 55 | TYPE = "type" 56 | TYPE_RDKIT = "RDkit" 57 | TYPE_OPENEYE = "OpenEye" 58 | TYPE_CORINA = "Corina" 59 | TYPE_LIGPREP = "Ligprep" 60 | TYPE_GOLD = "Gold" 61 | TYPE_OMEGA = "Omega" 62 | 63 | # structural alignment to reference ("internal" method) 64 | # --------- 65 | ALIGN = "align" 66 | ALIGN_MODE = "mode" 67 | ALIGN_MODE_INTERNAL = "internal" 68 | ALIGN_REFERENCE_PATHS = "reference_paths" 69 | ALIGN_REFERENCE_FORMAT = "reference_format" 70 | ALIGN_REFERENCE_FORMAT_SDF = "SDF" 71 | ALIGN_REFERENCE_FORMAT_PDB = "PDB" 72 | ALIGN_MINIMUM_SUBSTRUCTURE_RATIO = "minimum_substructure_ratio" 73 | ALIGN_COMPLETE_RINGS_ONLY = "complete_rings_only" 74 | 75 | # what to do in cases, where no alignment can be made, define what to do 76 | ALIGN_FAIL_ACTION = "fail_action" 77 | ALIGN_FAIL_DISCARD = "discard" 78 | ALIGN_FAIL_KEEP = "keep" 79 | 80 | # try to find the internal value and return 81 | def __getattr__(self, name): 82 | if name in self: 83 | return name 84 | raise AttributeError 85 | 86 | # prohibit any attempt to set any values 87 | def __setattr__(self, key, value): 88 | raise ValueError("No changes allowed.") 89 | -------------------------------------------------------------------------------- /dockstream/utils/enums/logging_enums.py: -------------------------------------------------------------------------------- 1 | 2 | class LoggingConfigEnum: 3 | """This "Enum" serves to store all paths and keywords used to configure the loggers.""" 4 | 5 | # set levels (for now, they match to the "logging" default ones) 6 | DEBUG = "debug" 7 | INFO = "info" 8 | WARNING = "warning" 9 | ERROR = "error" 10 | EXCEPTION = "exception" 11 | 12 | # paths to the configuration JSONs that are shipped with DockStream 13 | PATH_CONFIG_DEFAULT = "dockstream/config/logging/default.json" 14 | PATH_CONFIG_VERBOSE = "dockstream/config/logging/verbose.json" 15 | PATH_CONFIG_DEBUG = "dockstream/config/logging/debug.json" 16 | 17 | # high-level loggers defined in the configurations 18 | LOGGER_INTERFACE = "command_line_interface" 19 | LOGGER_TARGET_PREPARATION = "target_preparation" 20 | LOGGER_LIGAND_PREPARATION = "ligand_preparation" 21 | LOGGER_DOCKING = "docking" 22 | LOGGER_BLANK = "blank" 23 | 24 | # try to find the internal value and return 25 | def __getattr__(self, name): 26 | if name in self: 27 | return name 28 | raise AttributeError 29 | 30 | # prohibit any attempt to set any values 31 | def __setattr__(self, key, value): 32 | raise ValueError("No changes allowed.") 33 | -------------------------------------------------------------------------------- /dockstream/utils/enums/stereo_enumeration_enums.py: -------------------------------------------------------------------------------- 1 | 2 | class StereoEnumerationEnum: 3 | 4 | # stereo-enumeration 5 | # --------- 6 | STEREO_ENUM = "stereo_enumeration" 7 | STEREO_ENUM_BACKEND = "stereo_backend" 8 | STEREO_ENUM_BACKEND_RDKIT = "RDkit" 9 | STEREO_ENUM_PARAMETERS = "parameters" 10 | 11 | # RDkit 12 | # --------- 13 | RDKIT_TRY_EMBEDDING = "try_embedding" 14 | RDKIT_UNIQUE = "unique" 15 | RDKIT_MAX_ISOMERS = "max_isomers" 16 | 17 | # try to find the internal value and return 18 | def __getattr__(self, name): 19 | if name in self: 20 | return name 21 | raise AttributeError 22 | 23 | # prohibit any attempt to set any values 24 | def __setattr__(self, key, value): 25 | raise ValueError("No changes allowed.") 26 | -------------------------------------------------------------------------------- /dockstream/utils/enums/tag_additions_enum.py: -------------------------------------------------------------------------------- 1 | 2 | class TagAdditionsEnum: 3 | 4 | TAG_NAME = "name" 5 | TAG_SMILES = "smiles" 6 | TAG_ORIGINAL_SMILES = "original_smiles" 7 | TAG_LIGAND_ID = "ligand_id" 8 | 9 | # try to find the internal value and return 10 | def __getattr__(self, name): 11 | if name in self: 12 | return name 13 | raise AttributeError 14 | 15 | # prohibit any attempt to set any values 16 | def __setattr__(self, key, value): 17 | raise ValueError("No changes allowed.") -------------------------------------------------------------------------------- /dockstream/utils/enums/target_preparation_enum.py: -------------------------------------------------------------------------------- 1 | 2 | class TargetPreparationEnum: 3 | """This "Enum" serves to store all the strings used in parsing "target preparation" configurations.""" 4 | 5 | TARGETPREP = "target_preparation" 6 | 7 | # header region 8 | # --------- 9 | HEADER = "header" 10 | ENVIRONMENT = "environment" 11 | ENVIRONMENT_EXPORT = "export" 12 | ENVIRONMENT_EXPORT_KEY = "key" 13 | ENVIRONMENT_EXPORT_VALUE = "value" 14 | 15 | INPUT_PATH = "input_path" 16 | 17 | # loggers 18 | # --------- 19 | LOGGING = "logging" 20 | LOGGING_ENABLED = "enabled" 21 | LOGGING_VERBOSITY = "verbosity" 22 | LOGGING_VERBOSITY_LOW = "low" 23 | LOGGING_VERBOSITY_HIGH = "high" 24 | LOGGING_LOGFILE = "logfile" 25 | 26 | # structure fixes 27 | # --------- 28 | FIX = "fixer" 29 | FIX_ENABLED = "enabled" 30 | FIX_STANDARDIZE = "standardize" 31 | FIX_MISSINGHEAVYATOMS = "fix_missing_heavy_atoms" 32 | FIX_MISSINGHYDROGENS = "fix_missing_hydrogens" 33 | FIX_MISSINGLOOPS = "fix_missing_loops" 34 | FIX_ADDWATERBOX = "add_water_box" 35 | FIX_REMOVEHETEROGENS = "remove_heterogens" 36 | FIX_PBDOUTPUTPATH = "fixed_pdb_path" 37 | 38 | # target preparation 39 | # --------- 40 | CAVITY = "cavity" 41 | CAVITY_METHOD = "method" 42 | 43 | CAVITY_METHOD_REFERENCE = "reference_ligand" 44 | CAVITY_REFERENCE_PATH = "reference_ligand_path" 45 | CAVITY_REFERENCE_FORMAT = "reference_ligand_format" 46 | CAVITY_REFERENCE_FORMAT_SDF = "SDF" 47 | CAVITY_REFERENCE_FORMAT_PDB = "PDB" 48 | 49 | # backend runs 50 | # --------- 51 | RUNS = "runs" 52 | 53 | RUNS_BACKEND = "backend" 54 | RUNS_BACKEND_RDOCK = "rDock" 55 | RUNS_BACKEND_OPENEYE = "OpenEye" 56 | RUNS_BACKEND_GOLD = "Gold" 57 | RUNS_BACKEND_AUTODOCKVINA = "AutoDockVina" 58 | 59 | RUNS_OUTPUT = "output" 60 | RUNS_PARAM = "parameters" 61 | RUNS_PARAM_PREFIX_EXECUTION = "prefix_execution" 62 | RUNS_PARAM_BINARY_LOCATION = "binary_location" 63 | 64 | # try to find the internal value and return 65 | def __getattr__(self, name): 66 | if name in self: 67 | return name 68 | raise AttributeError 69 | 70 | # prohibit any attempt to set any values 71 | def __setattr__(self, key, value): 72 | raise ValueError("No changes allowed.") 73 | -------------------------------------------------------------------------------- /dockstream/utils/enums/taut_enum_enums.py: -------------------------------------------------------------------------------- 1 | 2 | class TautEnumEnum: 3 | """This "Enum" serves to store all keywords that are used by the "taut_enum" executable.""" 4 | 5 | TAUTENUM = "taut_enum" 6 | TAUTENUM_I = "-I" 7 | TAUTENUM_O = "-O" 8 | TAUTENUM_HELP = "--help" 9 | TAUTENUM_HELP_IDENTIFICATION_STRING = "Allowed Options" 10 | TAUTENUM_ENUM_PROTO = "--enumerate-protonation" 11 | TAUTENUM_ORI_ENUM = "--original-enumeration" 12 | TAUTENUM_ADD_NUMBERS = "--add-numbers-to-name" 13 | 14 | # try to find the internal value and return 15 | def __getattr__(self, name): 16 | if name in self: 17 | return name 18 | raise AttributeError 19 | 20 | # prohibit any attempt to set any values 21 | def __setattr__(self, key, value): 22 | raise ValueError("No changes allowed.") 23 | -------------------------------------------------------------------------------- /dockstream/utils/enums/transformations_enums.py: -------------------------------------------------------------------------------- 1 | 2 | class TransformationEnum: 3 | 4 | TRANSFORMATIONS = "transformations" 5 | TRANSFORMATION_TYPE = "type" 6 | TRANSFORMATION_TYPE_SMIRKS = "smirks" 7 | TRANSFORMATION_BACKEND = "backend" 8 | TRANSFORMATION_BACKEND_OPENEYE = "OpenEye" 9 | TRANSFORMATION_SMIRKS = "smirks" 10 | TRANSFORMATION_FAIL_ACTION = "fail_action" 11 | TRANSFORMATION_FAIL_ACTION_KEEP = "keep" 12 | TRANSFORMATION_FAIL_ACTION_DISCARD = "discard" 13 | 14 | # try to find the internal value and return 15 | def __getattr__(self, name): 16 | if name in self: 17 | return name 18 | raise AttributeError 19 | 20 | # prohibit any attempt to set any values 21 | def __setattr__(self, key, value): 22 | raise ValueError("No changes allowed.") 23 | -------------------------------------------------------------------------------- /dockstream/utils/execute_external/AutodockVina.py: -------------------------------------------------------------------------------- 1 | from dockstream.utils.enums.AutodockVina_enums import AutodockVinaExecutablesEnum 2 | from dockstream.utils.execute_external.execute import ExecutorBase 3 | 4 | 5 | EE = AutodockVinaExecutablesEnum() 6 | 7 | 8 | class AutodockVinaExecutor(ExecutorBase): 9 | 10 | def __init__(self, prefix_execution=None, binary_location=None): 11 | super().__init__(prefix_execution=prefix_execution, binary_location=binary_location) 12 | 13 | def execute(self, command: str, arguments: list, check=True, location=None): 14 | # check, whether a proper executable is provided 15 | if command not in [EE.VINA]: 16 | raise ValueError("Parameter command must be an dictionary of the internal AutoDock Vina executable list.") 17 | 18 | return super().execute(command=command, 19 | arguments=arguments, 20 | check=check, 21 | location=None) 22 | 23 | def is_available(self): 24 | try: 25 | result = self.execute(command=EE.VINA, 26 | arguments=[EE.VINA_VERSION], 27 | check=True) 28 | 29 | # do not use return code, because this will not work when wrapped another time 30 | if EE.VINA_VERSION_IDENTIFICATION_STRING in result.stdout: 31 | return True 32 | return False 33 | except Exception as e: 34 | return False 35 | -------------------------------------------------------------------------------- /dockstream/utils/execute_external/Corina.py: -------------------------------------------------------------------------------- 1 | from dockstream.utils.enums.Corina_enums import CorinaExecutablesEnum 2 | from dockstream.utils.execute_external.execute import ExecutorBase 3 | 4 | 5 | EE = CorinaExecutablesEnum() 6 | 7 | 8 | class CorinaExecutor(ExecutorBase): 9 | """For the execution of the "Corina" binary.""" 10 | 11 | def __init__(self, prefix_execution=None, binary_location=None): 12 | super().__init__(prefix_execution=prefix_execution, binary_location=binary_location) 13 | 14 | def execute(self, command: str, arguments: list, check=True, location=None): 15 | # check, whether a proper executable is provided 16 | if command not in [EE.CORINA]: 17 | raise ValueError("Parameter command must be an dictionary of the internal Corina executable list.") 18 | 19 | return super().execute(command=command, 20 | arguments=arguments, 21 | check=check, 22 | location=location) 23 | 24 | def is_available(self): 25 | # unfortunately, "Corina" does not return a meaningful return value (always '1'), so instead try to parse 26 | # the "stderr" of the help message 27 | try: 28 | result = self.execute(command=EE.CORINA, 29 | arguments=[EE.CORINA_HELP], 30 | check=False) 31 | if EE.CORINA_HELP_IDENTIFICATION_STRING in result.stderr: 32 | return True 33 | return False 34 | except Exception as e: 35 | return False 36 | -------------------------------------------------------------------------------- /dockstream/utils/execute_external/Gold.py: -------------------------------------------------------------------------------- 1 | from dockstream.utils.enums.Gold_enums import GoldExecutablesEnum 2 | from dockstream.utils.execute_external.execute import ExecutorBase 3 | 4 | 5 | EE = GoldExecutablesEnum() 6 | 7 | 8 | class GoldExecutor(ExecutorBase): 9 | """For the execution of "Gold" binaries.""" 10 | 11 | def __init__(self, prefix_execution=None, binary_location=None): 12 | super().__init__(prefix_execution=prefix_execution, binary_location=binary_location) 13 | 14 | def execute(self, command: str, arguments: list, check=True, location=None): 15 | # check, whether a proper executable is provided 16 | if command not in [EE.GOLD_AUTO]: 17 | raise ValueError("Parameter command must be an dictionary of the internal Gold executable list.") 18 | 19 | return super().execute(command=command, 20 | arguments=arguments, 21 | check=check, 22 | location=location) 23 | 24 | def is_available(self): 25 | try: 26 | result = self.execute(command=EE.GOLD_AUTO, 27 | arguments=[EE.GOLD_AUTO_HELP], 28 | check=False) 29 | 30 | # do not use return code, because this will not work when wrapped another time 31 | if EE.GOLD_AUTO_HELP_IDENTIFICATION_STRING in result.stdout: 32 | return True 33 | return False 34 | except Exception as e: 35 | return False 36 | -------------------------------------------------------------------------------- /dockstream/utils/execute_external/OE_Hybrid.py: -------------------------------------------------------------------------------- 1 | from dockstream.utils.enums.OE_Hybrid_enums import OpenEyeHybridExecutablesEnum 2 | from dockstream.utils.execute_external.execute import ExecutorBase 3 | 4 | EE = OpenEyeHybridExecutablesEnum() 5 | 6 | 7 | class OpenEyeHybridExecutor(ExecutorBase): 8 | """For the execution of OpenEye Hybrid docking which optimizes enrichment""" 9 | 10 | def __init__(self, prefix_execution="module load oedocking", binary_location=None): 11 | super().__init__(prefix_execution=prefix_execution, binary_location=binary_location) 12 | 13 | def execute(self, command: str, arguments: list, check=True, location=None): 14 | # check, whether a proper executable is provided 15 | if command not in [EE.HYBRID]: 16 | raise ValueError("Parameter command must be a dictionary of the internal OpenEye Hybrid executable list.") 17 | 18 | return super().execute(command=command, 19 | arguments=arguments, 20 | check=check, 21 | location=location) 22 | 23 | def is_available(self): 24 | try: 25 | result = self.execute(command=EE.HYBRID, 26 | arguments=[EE.OE_HYBRID_HELP_SIMPLE], 27 | check=False) 28 | 29 | # do not use return code, because this will not work when wrapped another time 30 | if EE.OE_HYBRID_HELP_IDENTIFICATION_STRING in result.stderr: 31 | return True 32 | return False 33 | except Exception as e: 34 | return False 35 | -------------------------------------------------------------------------------- /dockstream/utils/execute_external/Omega.py: -------------------------------------------------------------------------------- 1 | from dockstream.utils.enums.Omega_enums import OmegaExecutablesEnum 2 | from dockstream.utils.execute_external.execute import ExecutorBase 3 | 4 | _OE = OmegaExecutablesEnum() 5 | 6 | 7 | class OmegaExecutor(ExecutorBase): 8 | """For the execution of the "OMEGA".""" 9 | 10 | def __init__(self, prefix_execution=None, binary_location=None): 11 | super().__init__(prefix_execution=prefix_execution, binary_location=binary_location) 12 | 13 | def execute(self, command: str, arguments: list, check=True, location=None): 14 | # check, whether a proper executable is provided 15 | if command not in [_OE.OMEGA]: 16 | raise ValueError("Command must be a valid parameter in the internal OMEGA dictionary.") 17 | 18 | return super().execute(command=command, 19 | arguments=arguments, 20 | check=check, 21 | location=location) 22 | 23 | def is_available(self): 24 | try: 25 | result = self.execute(command=_OE.OMEGA, 26 | arguments=[_OE.HELP_SIMPLE], 27 | check=False) 28 | 29 | if _OE.OMEGA_HELP_IDENTIFICATION_STRING in result.stdout: 30 | return True 31 | return False 32 | except Exception as e: 33 | return False -------------------------------------------------------------------------------- /dockstream/utils/execute_external/OpenBabel.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from dockstream.utils.enums.OpenBabel_enums import OpenBabelExecutablesEnum 4 | from dockstream.utils.execute_external.execute import ExecutorBase 5 | 6 | EE = OpenBabelExecutablesEnum() 7 | 8 | 9 | class OpenBabelExecutor(ExecutorBase): 10 | """For the execution of the "obabel" binary.""" 11 | 12 | def __init__(self): 13 | # in case the environment is not activated, add the path to the binary here 14 | obabel_location = os.path.dirname(sys.executable) 15 | super().__init__(prefix_execution=None, binary_location=obabel_location) 16 | 17 | def execute(self, command: str, arguments: list, check=True, location=None): 18 | # check, whether a proper executable is provided 19 | if command not in [EE.OBABEL]: 20 | raise ValueError("Parameter command must be an element of the internal OpenBabel executable list.") 21 | 22 | return super().execute(command=command, 23 | arguments=arguments, 24 | check=check, 25 | location=location) 26 | 27 | def is_available(self): 28 | # unfortunately, "obabel" does not return a meaningful return value (always '1'), so instead try to parse 29 | # the "stdout" of the standard message; note, that "OpenBabel" is part of the environment and should always work 30 | try: 31 | result = self.execute(command=EE.OBABEL, 32 | arguments=[], 33 | check=False) 34 | if EE.OBABEL_IDENTIFICATION_STRING in result.stdout: 35 | return True 36 | return False 37 | except Exception as e: 38 | return False 39 | -------------------------------------------------------------------------------- /dockstream/utils/execute_external/Schrodinger.py: -------------------------------------------------------------------------------- 1 | from dockstream.utils.enums.Schrodinger_enums import SchrodingerExecutablesEnum 2 | from dockstream.utils.execute_external.execute import ExecutorBase 3 | 4 | 5 | EE = SchrodingerExecutablesEnum() 6 | 7 | 8 | class SchrodingerExecutor(ExecutorBase): 9 | """For the execution of "Schrodinger" binaries.""" 10 | 11 | def __init__(self, prefix_execution=None, binary_location=None): 12 | super().__init__(prefix_execution=prefix_execution, binary_location=binary_location) 13 | 14 | def execute(self, command: str, arguments: list, check=True, location=None, tokenGuard=None): 15 | # if a token guard has been configured, check if enough license tokens are available for the execution 16 | if tokenGuard is not None: 17 | tokenGuard.guard() 18 | 19 | # for Schrodinger commands, we need to provide the path to the binaries; we expect an environment variable 20 | # called "SCHRODINGER" at this stage and replace the command with the appropriate call 21 | if command == EE.GLIDE: 22 | command = EE.GLIDE_CALL 23 | elif command == EE.SDCONVERT: 24 | command = EE.SDCONVERT_CALL 25 | elif command == EE.LIGPREP: 26 | command = EE.LIGPREP_CALL 27 | else: 28 | raise ValueError("Parameter command must be an dictionary of the internal Schrodinger executable list.") 29 | return super().execute(command=command, 30 | arguments=arguments, 31 | check=check, 32 | location=location) 33 | 34 | def is_available(self): 35 | try: 36 | result = self.execute(command=EE.GLIDE, 37 | arguments=[EE.GLIDE_HELP], 38 | check=True) 39 | 40 | if EE.GLIDE_HELP_IDENTIFICATION_STRING in result.stdout: 41 | return True 42 | return False 43 | except Exception as e: 44 | return False 45 | -------------------------------------------------------------------------------- /dockstream/utils/execute_external/TautEnum.py: -------------------------------------------------------------------------------- 1 | from dockstream.utils.enums.taut_enum_enums import TautEnumEnum 2 | from dockstream.utils.execute_external.execute import ExecutorBase 3 | 4 | 5 | EE = TautEnumEnum() 6 | 7 | 8 | class TautEnumExecutor(ExecutorBase): 9 | """For the execution of the "TautEnum" binary.""" 10 | 11 | def __init__(self, prefix_execution=None, binary_location=None): 12 | super().__init__(prefix_execution=prefix_execution, binary_location=binary_location) 13 | 14 | def execute(self, command: str, arguments: list, check=True, location=None): 15 | # check, whether a proper executable is provided 16 | if command not in [EE.TAUTENUM]: 17 | raise ValueError("Parameter command must be an dictionary of the internal TautEnum executable list.") 18 | 19 | return super().execute(command=command, 20 | arguments=arguments, 21 | check=check, 22 | location=location) 23 | 24 | def is_available(self): 25 | # unfortunately, "TautEnum" does not seem to return a meaningful return value, so instead try to parse 26 | # the "stdout" of the help message 27 | try: 28 | result = self.execute(command=EE.TAUTENUM, 29 | arguments=[EE.TAUTENUM_HELP], 30 | check=False) 31 | if EE.TAUTENUM_HELP_IDENTIFICATION_STRING in result.stdout: 32 | return True 33 | return False 34 | except Exception as e: 35 | return False 36 | -------------------------------------------------------------------------------- /dockstream/utils/execute_external/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/utils/execute_external/__init__.py -------------------------------------------------------------------------------- /dockstream/utils/execute_external/execute.py: -------------------------------------------------------------------------------- 1 | import os 2 | import abc 3 | import subprocess 4 | from shlex import quote 5 | 6 | 7 | class ExecutorBase(metaclass=abc.ABCMeta): 8 | """Virtual base class for the general and program-specific executors.""" 9 | 10 | def __init__(self, prefix_execution=None, binary_location=None): 11 | # if something needs to be attached to the execution string each time, store it here; if not, value is "None" 12 | self._prefix_execution = prefix_execution 13 | self._binary_location = binary_location 14 | 15 | @abc.abstractmethod 16 | def execute(self, command: str, arguments: list, check=True, location=None): 17 | # to avoid security issues, escape the arguments 18 | arguments = [quote(str(arg)) for arg in arguments] 19 | 20 | # check, if command (binary) is to be found at a specific location (rather than in $PATH) 21 | if self._binary_location is not None: 22 | command = os.path.join(self._binary_location, command) 23 | 24 | # check, if the something needs to be added before the execution of the "rDock" command 25 | if self._prefix_execution is not None: 26 | command = self._prefix_execution + " && " + command 27 | 28 | # execute; if "location" is set, change to this directory and execute there 29 | complete_command = [command + ' ' + ' '.join(str(e) for e in arguments)] 30 | old_cwd = os.getcwd() 31 | if location is not None: 32 | os.chdir(location) 33 | result = subprocess.run(complete_command, 34 | check=check, # force python to raise exception if anything goes wrong 35 | universal_newlines=True, # convert output to string (instead of byte array) 36 | stdout=subprocess.PIPE, 37 | stderr=subprocess.PIPE, 38 | shell=True) 39 | os.chdir(old_cwd) 40 | return result 41 | 42 | @abc.abstractmethod 43 | def is_available(self): 44 | raise NotImplementedError("Overwrite this method in the child class.") 45 | 46 | 47 | class Executor(ExecutorBase): 48 | """For execution of command-line programs that do not have any specific executor themselves.""" 49 | 50 | def __init__(self, prefix_execution=None, binary_location=None): 51 | super().__init__(prefix_execution=prefix_execution, binary_location=binary_location) 52 | 53 | def execute(self, command: str, arguments: list, check=True, location=None): 54 | return super().execute(command=command, 55 | arguments=arguments, 56 | check=check, 57 | location=location) 58 | 59 | def is_available(self): 60 | raise NotImplementedError("Cannot reliably check, whether a random program executes properly - do not use.") 61 | 62 | -------------------------------------------------------------------------------- /dockstream/utils/execute_external/rDock.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import shutil 4 | from dockstream.utils.files_paths import move_up_directory 5 | from dockstream.utils.enums.rDock_enums import rDockExecutablesEnum 6 | from dockstream.utils.execute_external.execute import ExecutorBase 7 | 8 | 9 | EE = rDockExecutablesEnum() 10 | 11 | 12 | class rDockExecutor(ExecutorBase): 13 | """For the execution of "rDock" binaries.""" 14 | 15 | def __init__(self, prefix_execution=None, binary_location=None): 16 | super().__init__(prefix_execution=prefix_execution, binary_location=binary_location) 17 | 18 | def get_root(self): 19 | if self._prefix_execution is not None: 20 | command = self._prefix_execution + " && which " + EE.RBDOCK 21 | result = subprocess.run([command], 22 | check=True, 23 | universal_newlines=True, 24 | stdout=subprocess.PIPE, 25 | stderr=subprocess.PIPE, 26 | shell=True) 27 | return move_up_directory(result.stdout, n=2) 28 | else: 29 | return move_up_directory(shutil.which(EE.RBDOCK), n=1) 30 | 31 | def set_env_vars(self): 32 | # get path to root and set it to "RBT_ROOT" (important for library imports) 33 | # also set "RBT_HOME" which is the home directory for the input files which HAVE TO BE specified 34 | # with relative paths 35 | os.environ[EE.RBT_ROOT] = self.get_root() 36 | os.environ[EE.RBT_HOME] = os.getcwd() 37 | 38 | def execute(self, command: str, arguments: list, check=True, location=None): 39 | # check, whether a proper executable is provided 40 | if command not in [EE.RBDOCK, EE.RBCAVITY]: 41 | raise ValueError("Parameter command must be an dictionary of the internal rDock executable list.") 42 | 43 | return super().execute(command=command, 44 | arguments=arguments, 45 | check=check, 46 | location=None) 47 | 48 | def is_available(self): 49 | try: 50 | result = self.execute(command=EE.RBDOCK, 51 | arguments=[EE.RBDOCK_HELP], 52 | check=True) 53 | 54 | # do not use return code, because this will not work when wrapped another time 55 | if EE.RBDOCK_HELP_IDENTIFICATION_STRING in result.stdout: 56 | return True 57 | return False 58 | except Exception as e: 59 | return False 60 | -------------------------------------------------------------------------------- /dockstream/utils/files_paths.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import json 4 | from pathlib import Path 5 | 6 | 7 | def wait_until_file_generation(path, interval_sec=1, maximum_sec=None) -> bool: 8 | """Function waits until a given file is created or a maximum duration is reached. Returns "True" if file 9 | got created and False if maximum duration is exceeded. Potentially runs forever if "maximum_sec" is "None".""" 10 | counter = 0 11 | while not os.path.exists(path): 12 | time.sleep(interval_sec) 13 | counter = counter + 1 14 | if maximum_sec is not None and counter * interval_sec >= maximum_sec: 15 | break 16 | if os.path.exists(path): 17 | return True 18 | else: 19 | return False 20 | 21 | 22 | def move_up_directory(path, n=1): 23 | """Function, to move up 'n' directories for a given "path".""" 24 | # add +1 to take file into account 25 | if os.path.isfile(path): 26 | n += 1 27 | for _ in range(n): 28 | path = os.path.dirname(os.path.abspath(path)) 29 | return path 30 | 31 | 32 | def attach_root_path(path): 33 | """Function to attach the root path of the module for a given "path".""" 34 | ROOT_DIR = move_up_directory(os.path.abspath(__file__), n=2) 35 | return os.path.join(ROOT_DIR, path) 36 | 37 | 38 | def lines_in_file(path): 39 | with open(path) as f: 40 | for i, l in enumerate(f): 41 | pass 42 | return i + 1 43 | 44 | 45 | def dict_from_json_file(path): 46 | with open(path, 'r') as f: 47 | return json.load(f) 48 | 49 | 50 | def any_in_file(path, strings): 51 | if isinstance(strings, str): 52 | strings = [strings] 53 | if os.path.isfile(path): 54 | with open(path, 'r') as f: 55 | file_raw = f.readlines() 56 | for string in strings: 57 | if any(string in line for line in file_raw): 58 | return True 59 | return False 60 | else: 61 | return False 62 | 63 | 64 | def generate_folder_structure(filepath: str): 65 | folder_path = os.path.dirname(filepath) 66 | Path(folder_path).mkdir(parents=True, exist_ok=True) 67 | -------------------------------------------------------------------------------- /dockstream/utils/general_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tempfile 3 | from dockstream.utils.files_paths import attach_root_path 4 | 5 | 6 | # dictionary convenience functions 7 | # --------- 8 | def nested_get(dictionary: dict, keys: list, default=None): 9 | if not isinstance(keys, list): 10 | keys = [keys] 11 | if dictionary is None: 12 | return default 13 | if not keys: 14 | return dictionary 15 | return nested_get(dictionary.get(keys[0]), keys[1:], default) 16 | 17 | 18 | def in_keys(dictionary: dict, keys: list) -> bool: 19 | if not isinstance(keys, list): 20 | keys = [keys] 21 | 22 | _dict = dictionary 23 | for key in keys: 24 | try: 25 | _dict = _dict[key] 26 | except KeyError: 27 | return False 28 | return True 29 | 30 | 31 | # parsing "setup.py" 32 | # --------- 33 | 34 | def parse_setuppy(): 35 | path = attach_root_path("setup.py") 36 | parsed_dict = {} 37 | with open(path, 'r') as f: 38 | lines = f.readlines() 39 | for line in lines: 40 | if "name" in line: 41 | parsed_dict["name"] = line[line.find('"')+len('"'):line.rfind('"')] 42 | if "version" in line: 43 | parsed_dict["version"] = line[line.find('"')+len('"'):line.rfind('"')] 44 | if "license" in line: 45 | parsed_dict["license"] = line[line.find('"')+len('"'):line.rfind('"')] 46 | if "author" in line: 47 | parsed_dict["author"] = line[line.find('"')+len('"'):line.rfind('"')] 48 | return parsed_dict 49 | 50 | 51 | # note that "text" is True (in contrast to the underlying "mkstemp") 52 | def gen_temp_file(suffix=None, prefix=None, dir=None, text=True) -> str: 53 | filehandler, path = tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir, text=text) 54 | os.close(filehandler) 55 | return path 56 | -------------------------------------------------------------------------------- /dockstream/utils/parallelization/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/utils/parallelization/__init__.py -------------------------------------------------------------------------------- /dockstream/utils/parallelization/general_utils.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def split_into_sublists(input_list, partitions=None, slice_size=None): 5 | if partitions is None and slice_size is None: 6 | raise ValueError("Either specify partitions or slice size.") 7 | 8 | return_list = [] 9 | start_indices = [] # store the global index of the first ligand 10 | 11 | len_input = len(input_list) 12 | 13 | if partitions is not None: 14 | chunk_size = int(math.ceil(len_input / partitions)) 15 | else: 16 | chunk_size = slice_size 17 | 18 | for i in range(0, len_input, chunk_size): 19 | start_indices.append(i) 20 | return_list.append(input_list[i:i + chunk_size]) 21 | return start_indices, return_list 22 | 23 | 24 | def get_progress_bar_string(done, total, prefix="", suffix="", decimals=1, length=100, fill='█'): 25 | percent = ("{0:." + str(decimals) + "f}").format(100 * (done / float(total))) 26 | filledLength = int(length * done // total) 27 | bar = fill * filledLength + '-' * (length - filledLength) 28 | return f"{prefix}|{bar}| {percent}% {suffix}" 29 | -------------------------------------------------------------------------------- /dockstream/utils/translations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/dockstream/utils/translations/__init__.py -------------------------------------------------------------------------------- /dockstream/utils/translations/molecule_translator.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from dockstream.utils.translations.translation import RDkitMolToOpenEyeMol, OpenEyeMolToRDkitMol 3 | from dockstream.utils.enums.ligand_preparation_enum import LigandPreparationEnum 4 | from dockstream.core.ligand.ligand import Ligand 5 | 6 | 7 | class MoleculeTranslator: 8 | 9 | def __init__(self, molecules: List[Ligand], force_mol_type=False): 10 | self._LP = LigandPreparationEnum() 11 | self._known_types = [self._LP.TYPE_RDKIT, self._LP.TYPE_OPENEYE, self._LP.TYPE_CORINA, 12 | self._LP.TYPE_GOLD, self._LP.TYPE_LIGPREP, self._LP.TYPE_OMEGA] 13 | 14 | if not isinstance(molecules, list): 15 | molecules = [molecules] 16 | self._molecules = molecules 17 | if force_mol_type is False: 18 | mol_type = molecules[0].get_mol_type() 19 | else: 20 | mol_type = force_mol_type 21 | if mol_type is None: 22 | raise Exception("Type None cannot be used in molecule translations.") 23 | if mol_type not in self._known_types: 24 | raise ValueError(f"Type {mol_type} not in list of supported types.") 25 | self._mol_type = mol_type 26 | 27 | def get_as_rdkit(self): 28 | return self._translate_molecules(self._molecules, from_type=self._mol_type, to_type=self._LP.TYPE_RDKIT) 29 | 30 | def get_as_openeye(self): 31 | return self._translate_molecules(self._molecules, from_type=self._mol_type, to_type=self._LP.TYPE_OPENEYE) 32 | 33 | def add_molecules(self, molecules: list): 34 | molecules = [mol.get_clone() for mol in molecules] 35 | for molecule in molecules: 36 | mol_type = molecule.get_mol_type() 37 | self._molecules = self._molecules + self._translate_molecules([molecule], mol_type, self._mol_type) 38 | 39 | def _translate_molecules(self, molecules, from_type, to_type, bySMILES=False) -> list: 40 | # TODO: cover case, where conformers have been added 41 | if from_type == to_type or from_type is None: 42 | return molecules 43 | else: 44 | buffer = [] 45 | for mol in molecules: 46 | if (from_type == self._LP.TYPE_RDKIT or from_type == self._LP.TYPE_CORINA or from_type == self._LP.TYPE_LIGPREP) and \ 47 | to_type == self._LP.TYPE_OPENEYE: 48 | buffer.append(Ligand(smile=mol.get_smile(), ligand_number=mol.get_ligand_number(), 49 | original_smile=mol.get_original_smile(), 50 | enumeration=mol.get_enumeration(), 51 | molecule=RDkitMolToOpenEyeMol(mol.get_molecule(), bySMILES=bySMILES), 52 | mol_type=self._LP.TYPE_OPENEYE, 53 | name=mol.get_name())) 54 | elif from_type == self._LP.TYPE_OPENEYE and \ 55 | (to_type == self._LP.TYPE_RDKIT or to_type == self._LP.TYPE_CORINA or to_type == self._LP.TYPE_LIGPREP): 56 | buffer.append(Ligand(smile=mol.get_smile(), ligand_number=mol.get_ligand_number(), 57 | original_smile=mol.get_original_smile(), 58 | enumeration=mol.get_enumeration(), 59 | molecule=OpenEyeMolToRDkitMol(mol.get_molecule(), bySMILES=bySMILES), 60 | mol_type=self._LP.TYPE_RDKIT, 61 | name=mol.get_name())) 62 | elif (from_type in [self._LP.TYPE_RDKIT, self._LP.TYPE_LIGPREP, self._LP.TYPE_CORINA, self._LP.TYPE_OMEGA]) and \ 63 | (to_type in [self._LP.TYPE_RDKIT, self._LP.TYPE_LIGPREP, self._LP.TYPE_CORINA, self._LP.TYPE_OMEGA]): 64 | buffer.append(Ligand(smile=mol.get_smile(), ligand_number=mol.get_ligand_number(), 65 | original_smile=mol.get_original_smile(), 66 | enumeration=mol.get_enumeration(), 67 | molecule=mol.get_molecule(), 68 | mol_type=to_type, 69 | name=mol.get_name())) 70 | else: 71 | raise ValueError(f"The translation of {from_type} to {to_type} is not yet supported.") 72 | return buffer 73 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: DockStream 2 | channels: 3 | - conda-forge 4 | - omnia 5 | - plotly 6 | - openeye 7 | - rdkit 8 | dependencies: 9 | - python = 3.7 10 | - jsonschema 11 | - rdkit >= 2021 12 | - matplotlib 13 | - scikit-learn 14 | - seaborn>=0.11.0 15 | - pandas 16 | - numpy 17 | - openeye-toolkits >= 2019 18 | - openbabel 19 | - openmm 20 | - scipy 21 | - pydantic 22 | - pdbfixer 23 | -------------------------------------------------------------------------------- /environment_full.yml: -------------------------------------------------------------------------------- 1 | name: DockStreamFull 2 | channels: 3 | - file:///opt/scp/software/ccdc/2020.0.1/Python_API_2020/ccdc_conda_channel 4 | - conda-forge 5 | - omnia 6 | - plotly 7 | - openeye 8 | - rdkit 9 | dependencies: 10 | - python = 3.7 11 | - csd-python-api>=3.0.1 12 | - jsonschema 13 | - rdkit >= 2021 14 | - matplotlib 15 | - scikit-learn 16 | - seaborn>=0.11.0 17 | - pandas 18 | - numpy 19 | - openeye-toolkits >= 2019 20 | - openbabel 21 | - openmm 22 | - scipy 23 | - pydantic 24 | - pdbfixer 25 | -------------------------------------------------------------------------------- /examples/docking/docking_csv_input.json: -------------------------------------------------------------------------------- 1 | { 2 | "docking": { 3 | "header": { 4 | "environment": { 5 | }, 6 | "logging": { 7 | "logfile": "/tests/junk/docking_csv_input.log" 8 | } 9 | }, 10 | "ligand_preparation": { 11 | "embedding_pools": [ 12 | { 13 | "pool_id": "RDkit", 14 | "type": "RDkit", 15 | "parameters": { 16 | "protonate": true, 17 | "coordinate_generation": { 18 | "method": "UFF", 19 | "maximum_iterations": 350 20 | } 21 | }, 22 | "input": { 23 | "standardize_smiles": false, 24 | "input_path": "/tests/tests_data/1UYD/ligands.csv", 25 | "type": "csv", 26 | "delimiter": ",", 27 | "columns": { 28 | "smiles": "smiles", 29 | "names": "name" 30 | } 31 | }, 32 | "output": { 33 | "conformer_path": "/tests/junk/ligands_csv_input_embedded.sdf", 34 | "format": "sdf" 35 | } 36 | } 37 | ] 38 | }, 39 | "docking_runs": [ 40 | { 41 | "backend": "rDock", 42 | "run_id": "rDock", 43 | "input_pools": ["RDkit"], 44 | "parameters": { 45 | "prefix_execution": "module load rDock", 46 | "number_poses": 2, 47 | "rbdock_prm_paths": ["/tests/tests_data/rDock/rbcavity_1UYD_updated.prm"], 48 | "parallelization": { 49 | "number_cores": 4 50 | } 51 | }, 52 | "output": { 53 | "poses": { "poses_path": "/tests/junk/rDock_ligands_csv_input.sdf" }, 54 | "scores": { "scores_path": "/tests/junk/rDock_ligands_csv_input.csv" } 55 | } 56 | } 57 | ] 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/docking/docking_sdf_input.json: -------------------------------------------------------------------------------- 1 | { 2 | "docking": { 3 | "header": { 4 | "environment": { 5 | }, 6 | "logging": { 7 | "logfile": "/tests/junk/docking_sdf_input.log" 8 | } 9 | }, 10 | "ligand_preparation": { 11 | "embedding_pools": [ 12 | { 13 | "pool_id": "RDkit", 14 | "type": "RDkit", 15 | "parameters": { 16 | "protonate": true, 17 | "coordinate_generation": { 18 | "method": "UFF", 19 | "maximum_iterations": 450 20 | } 21 | }, 22 | "input": { 23 | "input_path": "/tests/tests_data/1UYD/ligands_aligned_tethered.sdf", 24 | "type": "sdf", 25 | "tags": { 26 | "names": "CUSTOM_NAME" 27 | } 28 | }, 29 | "output": { 30 | "conformer_path": "/tests/junk/ligands_sdf_input_embedded.sdf", 31 | "format": "sdf" 32 | } 33 | } 34 | ] 35 | }, 36 | "docking_runs": [ 37 | { 38 | "backend": "rDock", 39 | "run_id": "rDock", 40 | "input_pools": ["RDkit"], 41 | "parameters": { 42 | "prefix_execution": "module load rDock", 43 | "number_poses": 2, 44 | "rbdock_prm_paths": ["/tests/tests_data/rDock/rbcavity_1UYD_updated.prm"], 45 | "parallelization": { 46 | "number_cores": 4 47 | } 48 | }, 49 | "output": { 50 | "poses": { "poses_path": "/tests/junk/rDock_ligands_sdf_input.sdf" }, 51 | "scores": { "scores_path": "/tests/junk/rDock_ligands_sdf_input.csv" } 52 | } 53 | } 54 | ] 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /examples/docking/parallelized_AutodockVina_enumerated.json: -------------------------------------------------------------------------------- 1 | { 2 | "docking": { 3 | "header": { 4 | "environment": {}, 5 | "logging": { 6 | "logfile": "/tests/junk/parallelized_AutodockVina_enumerated.log" 7 | } 8 | }, 9 | "ligand_preparation": { 10 | "embedding_pools": [ 11 | { 12 | "pool_id": "RDkit", 13 | "type": "RDkit", 14 | "parameters": { 15 | "protonate": true, 16 | "coordinate_generation": { 17 | "method": "UFF", 18 | "maximum_iterations": 600 19 | } 20 | }, 21 | "input": { 22 | "standardize_smiles": false, 23 | "input_path": "/tests/tests_data/1UYD/ligands_smiles_taut_enum.smi", 24 | "type": "smi", 25 | "use_taut_enum": { 26 | "prefix_execution": "module load taut_enum", 27 | "enumerate_protonation": true 28 | } 29 | } 30 | } 31 | ] 32 | }, 33 | "docking_runs": [ 34 | { 35 | "backend": "AutoDockVina", 36 | "run_id": "AutoDockVina", 37 | "input_pools": ["RDkit"], 38 | "parameters": { 39 | "binary_location": "/foreign/AutoDockVina/autodock_vina_1_1_2_linux_x86/bin", 40 | "parallelization": { 41 | "number_cores": 4 42 | }, 43 | "seed": 42, 44 | "receptor_pdbqt_path": ["/tests/tests_data/AutoDockVina/1UYD_fixed.pdbqt"], 45 | "number_poses": 2, 46 | "search_space": { 47 | "--center_x": 3.3, 48 | "--center_y": 11.5, 49 | "--center_z": 24.8, 50 | "--size_x": 15, 51 | "--size_y": 10, 52 | "--size_z": 10 53 | } 54 | }, 55 | "output": { 56 | "poses": { "poses_path": "/tests/junk/AutodockVina_parallelized_enumerated.sdf" }, 57 | "scores": { "scores_path": "/tests/junk/AutodockVina_parallelized_enumerated.csv" } 58 | } 59 | } 60 | ] 61 | } 62 | } -------------------------------------------------------------------------------- /examples/docking/parallelized_Gold_enumerated.json: -------------------------------------------------------------------------------- 1 | { 2 | "docking": { 3 | "header": { 4 | "environment":{ 5 | "export": [ 6 | {"key": "CSDHOME", "value": "/opt/scp/software/ccdc/2020.0.1/CSD_2020"} 7 | ] 8 | }, 9 | "logging": { 10 | "logfile": "/tests/junk/parallelized_Gold_enumerated.log" 11 | } 12 | }, 13 | "ligand_preparation": { 14 | "embedding_pools": [ 15 | { 16 | "pool_id": "Corina_pool", 17 | "type": "Corina", 18 | "parameters": { 19 | "prefix_execution": "module load corina" 20 | }, 21 | "input": { 22 | "standardize_smiles": false, 23 | "input_path": "/tests/tests_data/1UYD/ligands_smiles_taut_enum.smi", 24 | "type": "smi", 25 | "use_taut_enum": { 26 | "prefix_execution": "module load taut_enum", 27 | "enumerate_protonation": true 28 | } 29 | }, 30 | "output": { 31 | "conformer_path": "/tests/junk/Corian_Gold_embedded.sdf", 32 | "format": "sdf" 33 | } 34 | } 35 | ] 36 | }, 37 | "docking_runs": [ 38 | { 39 | "backend": "Gold", 40 | "run_id": "Gold_from_corina", 41 | "input_pools": ["Corina_pool"], 42 | "parameters": { 43 | "prefix_execution": "module load ccdc/2020.0.1", 44 | "parallelization": { 45 | "number_cores": 2, 46 | "max_compounds_per_subjob": 4 47 | }, 48 | "receptor_paths": ["/tests/tests_data/Gold/Gold_binding_site.pkl"], 49 | "fitness_function": "plp", 50 | "response_value": "fitness", 51 | "early_termination": true, 52 | "autoscale": 25, 53 | "ndocks": 3 54 | }, 55 | "output": { 56 | "poses": { "poses_path": "/tests/junk/gold_fitness_corina_enumerated.sdf", "overwrite": false }, 57 | "scores": { "scores_path": "/tests/junk/gold_fitness_corina_enumerated.csv", "overwrite": false } 58 | } 59 | }, 60 | { 61 | "backend": "Gold", 62 | "run_id": "Gold_from_corina", 63 | "input_pools": ["Corina_pool"], 64 | "parameters": { 65 | "prefix_execution": "module load ccdc/2020.0.1", 66 | "parallelization": { 67 | "number_cores": 4, 68 | "max_compounds_per_subjob": 2 69 | }, 70 | "receptor_paths": ["/tests/tests_data/Gold/Gold_binding_site.pkl"], 71 | "fitness_function": "plp", 72 | "response_value": "value", 73 | "early_termination": true, 74 | "autoscale": 25, 75 | "ndocks": 3 76 | }, 77 | "output": { 78 | "poses": { "poses_path": "/tests/junk/gold_value_corina_enumerated.sdf", "overwrite": false }, 79 | "scores": { "scores_path": "/tests/junk/gold_value_corina_enumerated.csv", "overwrite": false } 80 | } 81 | } 82 | ] 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /examples/docking/parallelized_Omega_Classic_Hybrid.json: -------------------------------------------------------------------------------- 1 | { 2 | "docking": { 3 | "header": { 4 | "environment": { 5 | "export": [ 6 | { 7 | "key": "OE_LICENSE", 8 | "value": "/opt/scp/software/oelicense/1.0/oe_license.seq1" 9 | } 10 | ] 11 | }, 12 | "logging": { 13 | "logfile": "/tests/junk/parallelized_Omega_Classic_Hybrid.log" 14 | } 15 | }, 16 | "ligand_preparation": { 17 | "embedding_pools": [ 18 | { 19 | "pool_id": "Omega_pool", 20 | "type": "Omega", 21 | "parameters": { 22 | "prefix_execution": "module load omega", 23 | "mode": "classic" 24 | }, 25 | "input": { 26 | "standardize_smiles": false, 27 | "input_path": "/tests/tests_data/1UYD/ligands_smiles.txt", 28 | "type": "smi" 29 | }, 30 | "output": { 31 | "conformer_path": "/tests/junk/Omega_Classic_prepped_ligands.sdf", 32 | "format": "sdf" 33 | } 34 | } 35 | ] 36 | }, 37 | "docking_runs": [ 38 | { 39 | "backend": "Hybrid", 40 | "run_id": "Hybrid", 41 | "input_pools": ["Omega_pool"], 42 | "parameters": { 43 | "prefix_execution": "module load oedocking", 44 | "receptor_paths": ["/tests/tests_data/OpenEyeHybrid/1UYD_reference_receptor.oeb"], 45 | "parallelization": { 46 | "number_cores": 4 47 | }, 48 | "number_poses": 1, 49 | "resolution": "High" 50 | }, 51 | "output": { 52 | "poses": { "poses_path": "/tests/junk/Omega_Classic_Hybrid_docked_poses.sdf" }, 53 | "scores": { "scores_path": "/tests/junk/Omega_Classic_Hybrid_docked_scores.csv" } 54 | } 55 | } 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /examples/docking/parallelized_rDock_enumerated.json: -------------------------------------------------------------------------------- 1 | { 2 | "docking": { 3 | "header": { 4 | "environment": { 5 | }, 6 | "logging": { 7 | "logfile": "/tests/junk/parallelized_rDock_enumerated.log" 8 | } 9 | }, 10 | "ligand_preparation": { 11 | "embedding_pools": [ 12 | { 13 | "pool_id": "RDkit", 14 | "type": "RDkit", 15 | "parameters": { 16 | "protonate": true, 17 | "coordinate_generation": { 18 | "method": "UFF", 19 | "maximum_iterations": 450 20 | } 21 | }, 22 | "input": { 23 | "standardize_smiles": false, 24 | "input_path": "/tests/tests_data/1UYD/ligands_smiles_taut_enum.smi", 25 | "type": "smi", 26 | "use_taut_enum": { 27 | "prefix_execution": "module load taut_enum", 28 | "enumerate_protonation": true 29 | } 30 | }, 31 | "output": { 32 | "conformer_path": "/tests/junk/LP_RDkit_enumerated.sdf", 33 | "format": "sdf" 34 | } 35 | } 36 | ] 37 | }, 38 | "docking_runs": [ 39 | { 40 | "backend": "rDock", 41 | "run_id": "rDock", 42 | "input_pools": ["RDkit"], 43 | "parameters": { 44 | "prefix_execution": "module load rDock", 45 | "number_poses": 2, 46 | "rbdock_prm_paths": ["/tests/tests_data/rDock/rbcavity_1UYD_updated.prm"], 47 | "parallelization": { 48 | "number_cores": 4, 49 | "max_compounds_per_subjob": 2 50 | } 51 | }, 52 | "output": { 53 | "poses": { "poses_path": "/tests/junk/rDock_parallelized_enumerated.sdf" }, 54 | "scores": { "scores_path": "/tests/junk/rDock_parallelized_enumerated.csv" } 55 | } 56 | } 57 | ] 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/ligand_preparation/corina_ligand_preparation.json: -------------------------------------------------------------------------------- 1 | { 2 | "docking": { 3 | "header": { 4 | "logging": { 5 | "logfile": "/junk/corina_ligand_preparation.log" 6 | } 7 | }, 8 | "ligand_preparation": { 9 | "embedding_pools": [ 10 | { 11 | "pool_id": "Corina_not_aligned", 12 | "type": "Corina", 13 | "parameters": { 14 | "prefix_execution": "module load corina" 15 | }, 16 | "input": { 17 | "standardize_smiles": false, 18 | "input_path": "/tests_data/1UYD/ligands_smiles_taut_enum.smi", 19 | "type": "smi", 20 | "use_taut_enum": { 21 | "prefix_execution": "module load taut_enum", 22 | "enumerate_protonation": true 23 | } 24 | }, 25 | "output": { 26 | "conformer_path": "/junk/LP_Corina_noalignment.sdf", 27 | "format": "sdf" 28 | } 29 | }, 30 | { 31 | "pool_id": "Corina_stereo", 32 | "type": "Corina", 33 | "parameters": { 34 | "prefix_execution": "module load corina", 35 | "enumerate_stereo": true 36 | }, 37 | "input": { 38 | "standardize_smiles": false, 39 | "input_path": "/tests_data/1UYD/ligands_smiles_taut_enum.smi", 40 | "type": "smi", 41 | "use_taut_enum": { 42 | "prefix_execution": "module load taut_enum", 43 | "enumerate_protonation": true 44 | } 45 | }, 46 | "output": { 47 | "conformer_path": "/junk/LP_Corina_stereo.sdf", 48 | "format": "sdf" 49 | } 50 | } 51 | ] 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /examples/ligand_preparation/ligprep_ligand_preparation.json: -------------------------------------------------------------------------------- 1 | { 2 | "docking": { 3 | "header": { 4 | "logging": { 5 | "logfile": "/junk/ligprep_ligand_preparation.log" 6 | } 7 | }, 8 | "ligand_preparation": { 9 | "embedding_pools": [ 10 | { 11 | "pool_id": "Ligprep", 12 | "type": "Ligprep", 13 | "parameters": { 14 | "prefix_execution": "module load schrodinger/2019-4", 15 | "token_guard": { 16 | "prefix_execution": "module load schrodinger/2019-4", 17 | "token_pools": { 18 | "LIGPREP_MAIN": 4, 19 | "SUITE_11DEC2020": 8 20 | }, 21 | "wait_interval_seconds": 30, 22 | "wait_limit_seconds": 900 23 | }, 24 | "parallelization": { 25 | "number_cores": 1, 26 | "max_compounds_per_subjob": 4 27 | }, 28 | "use_epik": { 29 | "target_pH": 7.0, 30 | "pH_tolerance": 2.0 31 | }, 32 | "chirality": { 33 | "max_number_stereoisomers": 10 34 | }, 35 | "filter_file": { 36 | "Total_charge": "!= 0" 37 | }, 38 | "force_field": "OPLS_2005" 39 | }, 40 | "input": { 41 | "standardize_smiles": false, 42 | "input_path": "/tests/tests_data/1UYD/ligands_smiles.txt", 43 | "type": "smi" 44 | }, 45 | "output": { 46 | "conformer_path": "/tests/junk/LP_LigPrep.sdf", 47 | "format": "sdf" 48 | } 49 | } 50 | ] 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /examples/ligand_preparation/omega_classic_ligand_preparation.json: -------------------------------------------------------------------------------- 1 | { 2 | "docking": { 3 | "header": { 4 | "logging": { 5 | "logfile": "/junk/Omega_Classic_ligand_preparation.log" 6 | } 7 | }, 8 | "ligand_preparation": { 9 | "embedding_pools": [ 10 | { 11 | "pool_id": "Omega_classic", 12 | "type": "Omega", 13 | "parameters": { 14 | "prefix_execution": "module load omega", 15 | "mode": "classic" 16 | }, 17 | "input": { 18 | "standardize_smiles": false, 19 | "input_path": "/tests_data/1UYD/ligands_smiles.txt", 20 | "type": "smi" 21 | }, 22 | "output": { 23 | "conformer_path": "/junk/Omega_Classic_prepped_ligands.sdf", 24 | "format": "sdf" 25 | } 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /examples/ligand_preparation/rdkit_stereo.json: -------------------------------------------------------------------------------- 1 | { 2 | "docking": { 3 | "header": { 4 | "environment": { 5 | }, 6 | "logging": { 7 | "logfile": "/tests/junk/LP_RDkit_stereo.log" 8 | } 9 | }, 10 | "ligand_preparation": { 11 | "embedding_pools": [ 12 | { 13 | "pool_id": "RDkit", 14 | "type": "RDkit", 15 | "parameters": { 16 | "protonate": true, 17 | "coordinate_generation": { 18 | "method": "UFF", 19 | "maximum_iterations": 600 20 | } 21 | }, 22 | "input": { 23 | "standardize_smiles": false, 24 | "input_path": "/tests/tests_data/1UYD/ligands_smiles_taut_enum.smi", 25 | "type": "smi", 26 | "use_taut_enum": { 27 | "prefix_execution": "module load taut_enum", 28 | "enumerate_protonation": true 29 | }, 30 | "stereo_enumeration": { 31 | "stereo_backend": "RDKit" 32 | } 33 | }, 34 | "output": { 35 | "conformer_path": "/tests/junk/LP_rdkit_stereo.sdf", 36 | "format": "sdf" 37 | } 38 | } 39 | ] 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/ligand_preparation/taut_enum_all_backends.json: -------------------------------------------------------------------------------- 1 | { 2 | "docking": { 3 | "header": { 4 | "environment": { 5 | }, 6 | "logging": { 7 | "logfile": "/tests/junk/LP_taut_enum_all_backends.log" 8 | } 9 | }, 10 | "ligand_preparation": { 11 | "embedding_pools": [ 12 | { 13 | "pool_id": "RDkit", 14 | "type": "RDkit", 15 | "parameters": { 16 | "protonate": true, 17 | "coordinate_generation": { 18 | "method": "UFF", 19 | "maximum_iterations": 600 20 | } 21 | }, 22 | "input": { 23 | "standardize_smiles": false, 24 | "input_path": "/tests/tests_data/1UYD/ligands_smiles_taut_enum.smi", 25 | "type": "smi", 26 | "use_taut_enum": { 27 | "prefix_execution": "module load taut_enum", 28 | "enumerate_protonation": true 29 | } 30 | }, 31 | "output": { 32 | "conformer_path": "/tests/junk/LP_taut_enum_rdkit.sdf", 33 | "format": "sdf" 34 | } 35 | }, 36 | { 37 | "pool_id": "OpenEye", 38 | "type": "OpenEye", 39 | "parameters": { 40 | }, 41 | "input": { 42 | "standardize_smiles": false, 43 | "input_path": "/tests/tests_data/1UYD/ligands_smiles_taut_enum.smi", 44 | "type": "smi", 45 | "use_taut_enum": { 46 | "prefix_execution": "module load taut_enum", 47 | "enumerate_protonation": true 48 | } 49 | }, 50 | "output": { 51 | "conformer_path": "/tests/junk/LP_taut_enum_openeye.sdf", 52 | "format": "sdf" 53 | } 54 | }, 55 | { 56 | "pool_id": "taut_enum_Corina", 57 | "type": "Corina", 58 | "parameters": { 59 | "prefix_execution": "module load corina" 60 | }, 61 | "input": { 62 | "standardize_smiles": false, 63 | "input_path": "/tests/tests_data/1UYD/ligands_smiles_taut_enum.smi", 64 | "type": "smi", 65 | "use_taut_enum": { 66 | "prefix_execution": "module load taut_enum", 67 | "enumerate_protonation": true 68 | } 69 | }, 70 | "output": { 71 | "conformer_path": "/tests/junk/LP_taut_enum_corina.sdf", 72 | "format": "sdf" 73 | } 74 | }, 75 | { 76 | "pool_id": "taut_enum_ligprep", 77 | "type": "Ligprep", 78 | "parameters": { 79 | "prefix_execution": "module load schrodinger/2019-4", 80 | "use_epik": { 81 | "target_pH": 7.0, 82 | "pH_tolerance": 2.0 83 | } 84 | }, 85 | "input": { 86 | "standardize_smiles": false, 87 | "input_path": "/tests/tests_data/1UYD/ligands_smiles_taut_enum.smi", 88 | "type": "smi", 89 | "use_taut_enum": { 90 | "prefix_execution": "module load taut_enum", 91 | "enumerate_protonation": true 92 | } 93 | }, 94 | "output": { 95 | "conformer_path": "/tests/junk/LP_taut_enum_ligprep_ionized.sdf", 96 | "format": "sdf" 97 | } 98 | } 99 | ] 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /examples/target_preparation/AutoDockVina_target_preparation.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_preparation": 3 | { 4 | "header": { 5 | "logging": { 6 | "logfile": "/junktarget_prep_autodockvina.log" 7 | } 8 | }, 9 | "input_path": "/tests_data/1UYD/1UYD_apo.pdb", 10 | "fixer": { 11 | "enabled": true, 12 | "standardize": true, 13 | "remove_heterogens": true, 14 | "fix_missing_heavy_atoms": true, 15 | "fix_missing_hydrogens": true, 16 | "fix_missing_loops": false, 17 | "add_water_box": false 18 | }, 19 | "runs": [ 20 | { 21 | "backend": "AutoDockVina", 22 | "output": { 23 | "receptor_path": "/junk/AutoDock_Vina_reflig.pdbqt" 24 | }, 25 | "parameters": { 26 | "pH": 7.4, 27 | "extract_box": { 28 | "reference_ligand_path": "/tests_data/1UYD/ligand_PU8.sdf", 29 | "reference_ligand_format": "SDF" 30 | } 31 | } 32 | } 33 | ] 34 | } 35 | } -------------------------------------------------------------------------------- /examples/target_preparation/Gold_target_preparation.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_preparation": 3 | { 4 | "header": { 5 | "environment":{ 6 | "export": [ 7 | {"key": "CSDHOME", "value": "/opt/scp/software/ccdc/2020.0.1/CSD_2020"} 8 | ] 9 | }, 10 | "logging": { 11 | "logfile": "/junk/target_prep_Gold.log" 12 | } 13 | }, 14 | "input_path": "/tests_data/1UYD/1UYD_apo.pdb", 15 | "fixer": { 16 | "enabled": true, 17 | "standardize": true, 18 | "remove_heterogens": true, 19 | "fix_missing_heavy_atoms": true, 20 | "fix_missing_hydrogens": true, 21 | "fix_missing_loops": false, 22 | "add_water_box": false 23 | }, 24 | "runs": [ 25 | { 26 | "backend": "Gold", 27 | "output": { 28 | "receptor_path": "/junk/Gold_receptor.pkl" 29 | }, 30 | "parameters": {}, 31 | "cavity": { 32 | "method": "reference_ligand", 33 | "reference_ligand_path": "//tests_data/1UYD/ligand_PU8.sdf", 34 | "distance": 7.0 35 | } 36 | } 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/target_preparation/OpenEye_target_preparation.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_preparation": 3 | { 4 | "header": { 5 | "environment":{ 6 | "export": [ 7 | {"key": "OE_LICENSE", "value": "/opt/scp/software/oelicense/1.0/oe_license.seq1"} 8 | ] 9 | }, 10 | "logging": { 11 | "logfile": "/junk/target_prep_OpenEye.log" 12 | } 13 | }, 14 | "input_path": "/tests_data/1UYD/1UYD_apo.pdb", 15 | "fixer": { 16 | "enabled": true, 17 | "standardize": true, 18 | "remove_heterogens": true, 19 | "fix_missing_heavy_atoms": true, 20 | "fix_missing_hydrogens": true, 21 | "fix_missing_loops": false, 22 | "add_water_box": false, 23 | "fixed_pdb_path": "/junk/target_prep_PDB_fixed.pdb" 24 | }, 25 | "runs": [ 26 | { 27 | "backend": "OpenEye", 28 | "output": { 29 | "receptor_path": "/junk/OpenEye_reflig.oeb" 30 | }, 31 | "parameters": {}, 32 | "cavity": { 33 | "method": "reference_ligand", 34 | "reference_ligand_path": "/tests_data/1UYD/ligand_PU8.sdf", 35 | "reference_ligand_format": "SDF" 36 | } 37 | }, 38 | { 39 | "backend": "OpenEye", 40 | "output": { 41 | "receptor_path": "/junk/OpenEye_hintlig.oeb" 42 | }, 43 | "parameters": {}, 44 | "cavity": { 45 | "method": "hint", 46 | "coordinates": [ 47 | -0.234, 48 | 12.78, 49 | 24 50 | ] 51 | } 52 | }, 53 | { 54 | "backend": "OpenEye", 55 | "output": { 56 | "receptor_path": "/junk/OpenEye_boxlig.oeb" 57 | }, 58 | "parameters": {}, 59 | "cavity": { 60 | "method": "box", 61 | "limits": [ 62 | 0.3, 1.2, 63 | 12.7, 23.6, 64 | -8.9, 11.2 65 | ] 66 | } 67 | } 68 | ] 69 | } 70 | } -------------------------------------------------------------------------------- /examples/target_preparation/rDock_target_preparation.json: -------------------------------------------------------------------------------- 1 | { 2 | "target_preparation": 3 | { 4 | "header": { 5 | "logging": { 6 | "logfile": "/junk/target_prep_rDock.log" 7 | } 8 | }, 9 | "input_path": "/1UYD/1UYD_apo.pdb", 10 | "fixer": { 11 | "enabled": true, 12 | "standardize": true, 13 | "remove_heterogens": true, 14 | "fix_missing_heavy_atoms": true, 15 | "fix_missing_hydrogens": true, 16 | "fix_missing_loops": false, 17 | "add_water_box": false, 18 | "fixed_pdb_path": "/junk/target_prep_PDB_fixed.pdb" 19 | }, 20 | "runs": [ 21 | { 22 | "backend": "rDock", 23 | "output": { 24 | "directory": "/junk" 25 | }, 26 | "parameters": { 27 | "prefix_execution": "module load rDock" 28 | }, 29 | "cavity": { 30 | "method": "reference_ligand", 31 | "reference_ligand_path": "/tests/tests_data/1UYD/ligand_PU8.sdf", 32 | "reference_ligand_format": "SDF", 33 | "prm_file": "/junk/tests_data/rDock/rbcavity_1UYD.prm" 34 | } 35 | }, 36 | { 37 | "backend": "rDock", 38 | "output": { 39 | "directory": "/junk" 40 | }, 41 | "parameters": { 42 | "prefix_execution": "module load rDock" 43 | }, 44 | "cavity": { 45 | "method": "reference_ligand", 46 | "reference_ligand_path": "/tests_data/1UYD/ligand_PU8.sdf", 47 | "reference_ligand_format": "SDF" 48 | } 49 | } 50 | ] 51 | } 52 | } -------------------------------------------------------------------------------- /install_GOLD.txt: -------------------------------------------------------------------------------- 1 | 1) get the module installed 2 | 2) activate it with the key 3 | 3) get the path to your CSD home: echo $CSDHOME 4 | 4) look for folder "Python_API_2020" (probably one folder up) 5 | 5) update conda channel environment.yml: 6 | /opt/scp/software/ccdc/2020.0.1/Python_API_2020/ccdc_conda_channel 7 | 6) either install environment or: 8 | conda install -c /opt/scp/software/ccdc/2020.0.1/Python_API_2020/ccdc_conda_channel Pillow six lxml numpy matplotlib 9 | conda install -c /opt/scp/software/ccdc/2020.0.1/Python_API_2020/ccdc_conda_channel csd-python-api 10 | 7) Finally,on Linux and macOS there are a few more environment variables that must be set to the CSD Python API to communicate with the installed CSD system. CSDHOME must point to the CSD_2020 directory within your CSD-System installation directory, e.g.: 11 | 12 | $ export CSDHOME=/home/my_ccdc_software_dir/CCDC/CSD_2020 13 | On Linux Only, assuming that PYTHONHOME stores the location of the correct Python installation: 14 | 15 | $ export LD_LIBRARY_PATH=$PYTHONHOME/lib:$PYTHONHOME/lib/python2.7/site-packages/ccdc/_lib:$LD_LIBRARY_PATH 16 | 17 | 18 | 19 | On another note, DO NOT activate the module before installing the environment. 20 | -------------------------------------------------------------------------------- /sample_user_input.json: -------------------------------------------------------------------------------- 1 | { 2 | "ligand_preparation": { 3 | "type": "FILL HERE", 4 | "target_ph": "FILL HERE", 5 | "ph_tolerance": "FILL HERE" 6 | }, 7 | "docking run": { 8 | "backend": "Glide", 9 | "glide_keywords": { 10 | "POSES_PER_LIG": "FILL HERE", 11 | "POSTDOCK_NPOSE": "FILL HERE", 12 | "PRECISION": "FILL HERE" 13 | } 14 | }, 15 | "data": { 16 | "input_path": "FILL HERE", 17 | "receptor_path": "FILL HERE", 18 | "output_path": "FILL HERE" 19 | } 20 | } -------------------------------------------------------------------------------- /sdf2smiles.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | import os 5 | import pandas as pd 6 | import argparse 7 | 8 | import rdkit.Chem as Chem 9 | 10 | from dockstream.utils.smiles import to_smiles 11 | 12 | 13 | if __name__ == "__main__": 14 | 15 | # get the input parameters and parse them 16 | parser = argparse.ArgumentParser(description="Implements simple translator taking an SDF file and spitting out SMILES.") 17 | parser.add_argument("-sdf", type=str, default=None, help="A path a SDF file.") 18 | parser.add_argument("-smi", type=str, default=None, required=False, help="A path an output text file.") 19 | parser.add_argument("-csv", type=str, default=None, required=False, help="A path an output CSV file.") 20 | parser.add_argument("-keep_stereo", action="store_true", help="If set, exported SMILES contain stereo-information.") 21 | parser.add_argument("-tags2columns", type=str, nargs='+', default=None, required=False, 22 | help="A list of strings for which tags should be transformed into columns.") 23 | args = parser.parse_args() 24 | 25 | if args.sdf is None or not os.path.isfile(args.sdf): 26 | raise Exception("Parameter \"-sdf\" must be a relative or absolute path to valid sdf file.") 27 | if args.smi is None and args.csv is None: 28 | raise Exception("At least one of the \"-smi\" or \"-csv\" output paths must be set.") 29 | 30 | molecules = [] 31 | for mol in Chem.SDMolSupplier(args.sdf): 32 | if mol is None: 33 | continue 34 | molecules.append(mol) 35 | 36 | # write out 37 | # --------- 38 | if args.smi is not None: 39 | with open(args.smi, 'w') as smi_file: 40 | for mol in molecules: 41 | smi_file.write(to_smiles(mol, isomericSmiles=args.keep_stereo) + "\n") 42 | 43 | if args.csv is not None: 44 | data_buffer = [] 45 | columns = ["Name", "SMILES"] 46 | tags2columns = [] 47 | if args.tags2columns is not None: 48 | tags2columns = args.tags2columns 49 | columns = columns + tags2columns 50 | for mol in molecules: 51 | # add default columns for this row 52 | row = [mol.GetProp("_Name"), 53 | to_smiles(mol, isomericSmiles=args.keep_stereo)] 54 | 55 | # add selected columns for this row (if specified) 56 | for tag in tags2columns: 57 | try: 58 | row.append(mol.GetProp(tag)) 59 | except KeyError: 60 | row.append(None) 61 | 62 | data_buffer.append(row) 63 | df_writeout = pd.DataFrame(data_buffer, columns=columns) 64 | df_writeout.to_csv(path_or_buf=args.csv, 65 | sep=',', 66 | na_rep='', 67 | header=True, 68 | index=False, 69 | mode='w', 70 | quoting=None) 71 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | long_description = file: README.md 4 | long_description_content_type = text/markdown 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from os import path 3 | 4 | here = path.abspath(path.dirname(__file__)) 5 | 6 | 7 | setup( 8 | name="DockStream", 9 | version="1.0.0", 10 | description=( 11 | "A comprehensive Python wrapper for a selection of molecule docking backends" 12 | ), 13 | license="Apache License 2.0", 14 | url="https://github.com/MolecularAI/DockStream", 15 | python_requires=">=3.6.1", 16 | classifiers=[ 17 | "Development Status :: 1 - Planning", 18 | "Natural Language :: English", 19 | "Programming Language :: Python :: 3.6", 20 | "Environment :: Console", 21 | "Intended Audience :: Developers", 22 | "License :: OSI Approved :: MIT License", 23 | "Libraries :: Application Frameworks" 24 | ], 25 | keywords="docking, molecular embedding, bio-physics", 26 | packages=find_packages(exclude=['docs', 'tests*']), 27 | include_package_data=True, 28 | author="Christian Margreitter", 29 | author_email="christian.margreitter@astrazeneca.com" 30 | ) 31 | -------------------------------------------------------------------------------- /smiles_clean_up.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | 4 | def smiles_cleaner(input_smiles: str, output_smiles: str): 5 | with open(input_smiles, 'r') as f: 6 | with open(output_smiles, 'w+') as new_f: 7 | for line in f.readlines(): 8 | fixed_line = line.split(' ')[0] 9 | new_f.write(f'{fixed_line}\n') 10 | 11 | 12 | if __name__ == '__main__': 13 | # take user specified input parameters to run the benchmarking script 14 | parser = argparse.ArgumentParser(description='Implements entry point to SMILES clean-up') 15 | parser.add_argument('-input_smiles', type=str, required=True, help='The path to a SMILES file') 16 | parser.add_argument('-output_smiles', type=str, required=True, help='The output path for the cleaned-up SMILES file') 17 | args = parser.parse_args() 18 | 19 | smiles_cleaner(args.input_smiles, args.output_smiles) 20 | -------------------------------------------------------------------------------- /tests/AutodockVina/__init__.py: -------------------------------------------------------------------------------- 1 | from tests.AutodockVina.test_AutoDockVina_target_preparation import * 2 | from tests.AutodockVina.test_AutoDockVina_backend import * 3 | -------------------------------------------------------------------------------- /tests/AutodockVina/test_AutoDockVina_target_preparation.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | import shutil 4 | from rdkit import Chem 5 | 6 | from dockstream.containers.target_preparation_container import TargetPreparationContainer 7 | from dockstream.core.AutodockVina.AutodockVina_target_preparator import AutodockVinaTargetPreparator 8 | 9 | from dockstream.utils.enums.AutodockVina_enums import AutodockTargetPreparationEnum 10 | from dockstream.utils.enums.OpenBabel_enums import OpenBabelExecutablesEnum 11 | from dockstream.utils.execute_external.OpenBabel import OpenBabelExecutor 12 | 13 | from tests.tests_paths import PATHS_1UYD, PATH_AUTODOCKVINA_EXAMPLES 14 | from dockstream.utils.files_paths import attach_root_path 15 | 16 | 17 | class Test_AutoDockVina_target_preparation(unittest.TestCase): 18 | 19 | @classmethod 20 | def setUpClass(cls): 21 | cls._TE = AutodockTargetPreparationEnum() 22 | cls._EE = OpenBabelExecutablesEnum() 23 | cls._original_path = os.getcwd() 24 | cls._working_dir = os.path.join(attach_root_path(PATH_AUTODOCKVINA_EXAMPLES.TARGET_PREP_FOLDER)) 25 | 26 | cls._OpenBabel_executor = OpenBabelExecutor() 27 | if not cls._OpenBabel_executor.is_available(): 28 | raise Exception("Could not load OpenBabel backend - abort.") 29 | 30 | # generate temporary folder and set current path there 31 | if not os.path.isdir(cls._working_dir): 32 | os.makedirs(cls._working_dir) 33 | os.chdir(cls._working_dir) 34 | 35 | def setUp(self) -> None: 36 | self.target = Chem.MolFromPDBFile(attach_root_path(PATHS_1UYD.TARGET_APO_PDB)) 37 | self._conf = {self._TE.TARGETPREP: { 38 | self._TE.INPUT_PATH: attach_root_path(PATHS_1UYD.TARGET_APO_PDB), 39 | self._TE.FIX: {self._TE.FIX_ENABLED: False}, 40 | self._TE.RUNS: [ 41 | { 42 | self._TE.RUNS_BACKEND: self._TE.RUNS_BACKEND_AUTODOCKVINA, 43 | self._TE.RUNS_OUTPUT: { 44 | self._TE.RECEPTOR_PATH: attach_root_path(PATH_AUTODOCKVINA_EXAMPLES.RECEPTOR) 45 | }, 46 | self._TE.RUNS_PARAM: { 47 | self._TE.PH: 7.4 48 | } 49 | } 50 | ] 51 | }} 52 | 53 | @classmethod 54 | def tearDownClass(cls): 55 | os.chdir(cls._original_path) 56 | if os.path.isdir(cls._working_dir): 57 | shutil.rmtree(cls._working_dir) 58 | 59 | def test_pdb2pdbqt(self): 60 | # specify PDBQT path 61 | pdbqt_path = os.path.join(self._working_dir, "test_pdbqt_gen.pdbqt") 62 | self._conf[self._TE.TARGETPREP][self._TE.RUNS][0][self._TE.RUNS_OUTPUT][self._TE.RECEPTOR_PATH] = pdbqt_path 63 | 64 | # write it out using openbabel 65 | conf = TargetPreparationContainer(conf=self._conf) 66 | prep = AutodockVinaTargetPreparator(conf=conf, target=self.target) 67 | prep._export_as_pdb2pdbqt(path=pdbqt_path) 68 | 69 | # check file size in bytes 70 | self.assertAlmostEqual(282410, os.stat(pdbqt_path).st_size, places=1) 71 | 72 | def test_ref_compound_box(self): 73 | self._conf[self._TE.TARGETPREP][self._TE.RUNS][0][self._TE.RUNS_PARAM][self._TE.EXTRACT_BOX] = { 74 | self._TE.EXTRACT_BOX_REFERENCE_LIGAND_PATH: attach_root_path(PATHS_1UYD.LIGAND_PU8_SDF), 75 | self._TE.EXTRACT_BOX_REFERENCE_LIGAND_FORMAT: self._TE.EXTRACT_BOX_REFERENCE_LIGAND_FORMAT_SDF 76 | } 77 | 78 | # write it out using openbabel 79 | conf = TargetPreparationContainer(conf=self._conf) 80 | prep = AutodockVinaTargetPreparator(conf=conf, target=self.target) 81 | x_coords, y_coords, z_coords = prep._extract_box() 82 | 83 | self.assertEqual(len(x_coords), 28) 84 | self.assertListEqual([4.403, 5.122, 5.091], x_coords[:3]) 85 | self.assertListEqual([15.528, 15.084, 13.786], y_coords[:3]) 86 | self.assertListEqual([26.579, 25.453, 24.846], z_coords[:3]) 87 | -------------------------------------------------------------------------------- /tests/Corina/__init__.py: -------------------------------------------------------------------------------- 1 | from tests.Corina.test_Corina_ligand_preparation import * 2 | -------------------------------------------------------------------------------- /tests/Gold/__init__.py: -------------------------------------------------------------------------------- 1 | from tests.Gold.test_Gold_target_preparation import * 2 | from tests.Gold.test_Gold_backend import * 3 | -------------------------------------------------------------------------------- /tests/Gold/test_Gold_target_preparation.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import unittest 4 | 5 | from tests.tests_paths import MAIN_CONFIG 6 | if "CSDHOME" in MAIN_CONFIG: 7 | os.environ["CSDHOME"] = MAIN_CONFIG["CSDHOME"] 8 | 9 | from dockstream.utils.enums.Gold_enums import GoldTargetKeywordEnum 10 | from dockstream.containers.target_preparation_container import TargetPreparationContainer 11 | from dockstream.core.Gold.Gold_target_preparator import GoldTargetPreparator 12 | 13 | from tests.tests_paths import PATHS_1UYD 14 | from dockstream.utils.files_paths import attach_root_path 15 | 16 | 17 | class Test_Gold_target_preparation(unittest.TestCase): 18 | 19 | @classmethod 20 | def setUpClass(cls): 21 | cls._original_path = os.getcwd() 22 | cls._working_dir = os.path.join(attach_root_path("tests/junk/Gold_target_prep")) 23 | 24 | # generate temporary folder and set current path there 25 | if not os.path.isdir(cls._working_dir): 26 | os.makedirs(cls._working_dir) 27 | os.chdir(cls._working_dir) 28 | 29 | cls._TE = GoldTargetKeywordEnum() 30 | 31 | def setUp(self): 32 | self.target_path = attach_root_path(PATHS_1UYD.TARGET_APO_PDB) 33 | 34 | self._conf = {self._TE.TARGETPREP: { 35 | self._TE.INPUT_PATH: attach_root_path(PATHS_1UYD.TARGET_APO_PDB), 36 | self._TE.FIX: {self._TE.FIX_ENABLED: False}, 37 | self._TE.RUNS: [ 38 | { 39 | self._TE.RUNS_BACKEND: self._TE.RUNS_BACKEND_GOLD, 40 | self._TE.RUNS_OUTPUT: {}, 41 | self._TE.RUNS_PARAM: {}, 42 | self._TE.CAVITY: { 43 | self._TE.CAVITY_METHOD: self._TE.CAVITY_METHOD_REFERENCE, 44 | self._TE.CAVITY_REFERENCE_PATH: attach_root_path(PATHS_1UYD.LIGAND_PU8_PDB), 45 | self._TE.CAVITY_REFERENCE_DISTANCE: 7.0 46 | } 47 | } 48 | ] 49 | }} 50 | 51 | @classmethod 52 | def tearDownClass(cls): 53 | os.chdir(cls._original_path) 54 | if os.path.isdir(cls._working_dir): 55 | shutil.rmtree(cls._working_dir) 56 | 57 | def test_initialization(self): 58 | conf = TargetPreparationContainer(conf=self._conf) 59 | 60 | # initialize with a PDB file path ("reference" method) 61 | prep_reference = GoldTargetPreparator(conf=conf, target=self.target_path, run_number=0) 62 | prep_reference.specify_cavity() 63 | prep_reference.write_target(path=os.path.join(self._working_dir, "Gold_binding_site.pkl")) 64 | dictionary = prep_reference._target_dict 65 | self.assertEqual(len(dictionary[self._TE.TARGET_PDB]), 1925) 66 | self.assertEqual(len(dictionary[self._TE.REFERENCE_LIGAND]), 28) 67 | self.assertEqual(dictionary[self._TE.CAVITY_REFERENCE_DISTANCE], 7.0) 68 | -------------------------------------------------------------------------------- /tests/Omega/__init__.py: -------------------------------------------------------------------------------- 1 | from tests.Omega.test_Omega_ligand_preparation import * -------------------------------------------------------------------------------- /tests/OpenEye/__init__.py: -------------------------------------------------------------------------------- 1 | from tests.OpenEye.test_OpenEye_ligand_preparation import * 2 | from tests.OpenEye.test_OpenEye_target_preparation import * 3 | from tests.OpenEye.test_OpenEye_backend import * 4 | from tests.OpenEye.test_OpenEye_transformer import * 5 | -------------------------------------------------------------------------------- /tests/OpenEye/test_OpenEye_transformer.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | 4 | from dockstream.utils.enums.transformations_enums import TransformationEnum 5 | from dockstream.utils.enums.OpenEye_enums import OpenEyeDockingConfigurationEnum, OpenEyeLigandPreparationEnum 6 | 7 | from dockstream.core.ligand.ligand import Ligand 8 | from dockstream.core.OpenEye.OpenEye_transformator import OpenEyeTransformator 9 | 10 | from tests.tests_paths import PATHS_1UYD, MAIN_CONFIG 11 | from dockstream.utils.files_paths import attach_root_path 12 | from dockstream.utils.smiles import read_smiles_file 13 | 14 | 15 | class Test_OpenEye_transformer(unittest.TestCase): 16 | 17 | @classmethod 18 | def setUpClass(cls): 19 | cls._LP = OpenEyeLigandPreparationEnum() 20 | cls._CE = OpenEyeDockingConfigurationEnum() 21 | cls._TE = TransformationEnum() 22 | if "OE_LICENSE" in MAIN_CONFIG: 23 | os.environ["OE_LICENSE"] = MAIN_CONFIG["OE_LICENSE"] 24 | 25 | def setUp(self): 26 | self.ligands_smiles = list(read_smiles_file(attach_root_path(PATHS_1UYD.LIGANDS_SMILES_TXT), standardize=False)) 27 | ligands = [] 28 | for smile_number, smile in enumerate(self.ligands_smiles): 29 | ligands.append(Ligand(smile=smile, ligand_number=smile_number)) 30 | self.ligands = ligands 31 | 32 | @classmethod 33 | def tearDownClass(cls): 34 | pass 35 | 36 | def test_smirk_transformation_keep(self): 37 | # use a smirk, that will attach a charge and a hydrogen atom to a given nitrogen 38 | conf = {self._TE.TRANSFORMATION_TYPE: self._TE.TRANSFORMATION_TYPE_SMIRKS, 39 | self._TE.TRANSFORMATION_BACKEND: self._TE.TRANSFORMATION_BACKEND_OPENEYE, 40 | self._TE.TRANSFORMATION_SMIRKS: "[c:1]1[n:2][c:3]2[c:4]([n:5][c:6][n;X2:7][c:8]2[n:9]1)>>[c:1]1[n:2][c:3]2[c:4]([n:5][c:6][n+:7]([H])[c:8]2[n:9]1)", 41 | self._TE.TRANSFORMATION_FAIL_ACTION: self._TE.TRANSFORMATION_FAIL_ACTION_KEEP} 42 | 43 | OE_transformator = OpenEyeTransformator(conf) 44 | self.assertListEqual(["C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21", 45 | "COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1", 46 | "Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12"], 47 | [self.ligands[index].get_smile() for index in [0, 13, 14]]) 48 | 49 | # the last smile does not have match the substructure and as "fail_action" is "keep" will remain untouched 50 | transformed_ligands = OE_transformator.transform(self.ligands) 51 | self.assertEqual(len(transformed_ligands), 15) 52 | self.assertListEqual(["COc1cc(c(c(c1OC)OC)Cl)Cc2nc3c(nc[nH+]c3n2CCCC#C)N", 53 | "COc1ccc(c(c1)Cc2[nH]c3c(nc([nH+]c3n2)F)N)OC", 54 | "Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12"], 55 | [self.ligands[index].get_smile() for index in [0, 13, 14]]) 56 | 57 | def test_smirk_transformation_discard(self): 58 | # use a smirk, that will attach a charge and a hydrogen atom to a given nitrogen 59 | conf = {self._TE.TRANSFORMATION_TYPE: self._TE.TRANSFORMATION_TYPE_SMIRKS, 60 | self._TE.TRANSFORMATION_BACKEND: self._TE.TRANSFORMATION_BACKEND_OPENEYE, 61 | self._TE.TRANSFORMATION_SMIRKS: "[c:1]1[n:2][c:3]2[c:4]([n:5][c:6][n;X2:7][c:8]2[n:9]1)>>[c:1]1[n:2][c:3]2[c:4]([n:5][c:6][n+:7]([H])[c:8]2[n:9]1)", 62 | self._TE.TRANSFORMATION_FAIL_ACTION: self._TE.TRANSFORMATION_FAIL_ACTION_DISCARD} 63 | 64 | OE_transformator = OpenEyeTransformator(conf) 65 | self.assertListEqual(["C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21", 66 | "COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1", 67 | "Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12"], 68 | [self.ligands[index].get_smile() for index in [0, 13, 14]]) 69 | 70 | # the last smile does not have match the substructure and as "fail_action" is "keep" will remain untouched 71 | transformed_ligands = OE_transformator.transform(self.ligands) 72 | self.assertEqual(len(transformed_ligands), 14) 73 | self.assertListEqual(["COc1cc(c(c(c1OC)OC)Cl)Cc2nc3c(nc[nH+]c3n2CCCC#C)N", 74 | "COc1ccc(c(c1)Cc2[nH]c3c(nc([nH+]c3n2)F)N)OC"], 75 | [self.ligands[index].get_smile() for index in [0, 13]]) 76 | -------------------------------------------------------------------------------- /tests/OpenEye_Hybrid/__init__.py: -------------------------------------------------------------------------------- 1 | from tests.OpenEye_Hybrid.test_OE_Hybrid_backend import * 2 | -------------------------------------------------------------------------------- /tests/RDkit/__init__.py: -------------------------------------------------------------------------------- 1 | from tests.RDkit.test_RDkit_ligand_preparation import * 2 | from tests.RDkit.test_RDkit_stereo_enumeration import * 3 | -------------------------------------------------------------------------------- /tests/RDkit/test_RDkit_stereo_enumeration.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from dockstream.core.RDkit.RDkit_stereo_enumerator import RDKitStereoEnumerator, RDKitStereoEnumeratorParameters 4 | 5 | from tests.tests_paths import PATHS_1UYD 6 | from dockstream.utils.files_paths import attach_root_path 7 | from dockstream.utils.smiles import read_smiles_file 8 | from dockstream.core.ligand.ligand import Ligand 9 | 10 | 11 | # TODO: move "prefix_execution" to "config/tests_config/config.json" 12 | class Test_RDkit_stereo_enumeration(unittest.TestCase): 13 | 14 | def setUp(self): 15 | smiles = list(read_smiles_file(attach_root_path(PATHS_1UYD.LIGANDS_SMILES_TXT), standardize=False)) 16 | 17 | # add one smiles that will result in more than one enumeration (unlike the 15 others) 18 | smiles.append("Cc1cc(cn1C)c2csc(n2)N=C(N)N") 19 | smiles.append("CC(C)(C)CCC1(c2ccccc2C(=O)C(C1=O)C3=NS(=O)(=O)c4cc(ccc4N3)NS(=O)(=O)C)NCc5cccc(c5)OC") 20 | 21 | self.ligands = [] 22 | for smile_number, smile in enumerate(smiles): 23 | self.ligands.append(Ligand(smile=smile, 24 | original_smile=smile, 25 | ligand_number=smile_number, 26 | enumeration=0, 27 | molecule=None, 28 | mol_type=None)) 29 | 30 | def test_RDkit_stereo_enumerator(self): 31 | enum = RDKitStereoEnumerator( 32 | parameters=RDKitStereoEnumeratorParameters( 33 | try_embedding=True, 34 | unique=True, 35 | max_isomers=1024)) 36 | enum_result = enum.enumerate(ligands=self.ligands) 37 | 38 | # check tautomer assignment 39 | list_smiles = [] 40 | list_ligand_numbers = [] 41 | list_enumeration_numbers = [] 42 | for result in enum_result: 43 | list_smiles.append(result.get_smile()) 44 | list_ligand_numbers.append(result.get_ligand_number()) 45 | list_enumeration_numbers.append(result.get_enumeration()) 46 | self.assertListEqual(list_smiles, 47 | ['C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21', 48 | 'CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21', 49 | 'CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)ncnc21', 50 | 'CCCCn1c(Cc2cccc(OC)c2)nc2c(N)ncnc21', 51 | 'C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)nc(F)nc21', 52 | 'CCCCn1c(Cc2ccc(OC)cc2)nc2c(N)ncnc21', 53 | 'CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)ncnc21', 54 | 'CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21', 55 | 'CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)nc(F)nc21', 56 | 'C#CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21', 57 | 'CC(C)NCCCn1c(Cc2cc3c(cc2I)OCO3)nc2c(N)nc(F)nc21', 58 | 'CC(C)NCCCn1c(Sc2cc3c(cc2Br)OCO3)nc2c(N)ncnc21', 59 | 'CC(C)NCCCn1c(Sc2cc3c(cc2I)OCO3)nc2c(N)ncnc21', 60 | 'COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1', 61 | 'Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12', 62 | 'Cc1cc(-c2csc(N=C(N)N)n2)cn1C', 63 | 'COc1cccc(CN[C@@]2(CCC(C)(C)C)C(=O)[C@@H](C3=NS(=O)(=O)c4cc(NS(C)(=O)=O)ccc4N3)C(=O)c3ccccc32)c1', 64 | 'COc1cccc(CN[C@@]2(CCC(C)(C)C)C(=O)[C@H](C3=NS(=O)(=O)c4cc(NS(C)(=O)=O)ccc4N3)C(=O)c3ccccc32)c1', 65 | 'COc1cccc(CN[C@]2(CCC(C)(C)C)C(=O)[C@@H](C3=NS(=O)(=O)c4cc(NS(C)(=O)=O)ccc4N3)C(=O)c3ccccc32)c1', 66 | 'COc1cccc(CN[C@]2(CCC(C)(C)C)C(=O)[C@H](C3=NS(=O)(=O)c4cc(NS(C)(=O)=O)ccc4N3)C(=O)c3ccccc32)c1']) 67 | self.assertListEqual(list_ligand_numbers, 68 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 16, 16]) 69 | self.assertListEqual(list_enumeration_numbers, 70 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3]) 71 | -------------------------------------------------------------------------------- /tests/Schrodinger/__init__.py: -------------------------------------------------------------------------------- 1 | from tests.Schrodinger.test_Schrodinger_backend import * 2 | from tests.Schrodinger.test_token_guard import * 3 | from tests.Schrodinger.test_ligprep_ligand_preparation import * 4 | -------------------------------------------------------------------------------- /tests/Schrodinger/test_token_guard.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from dockstream.core.Schrodinger.license_token_guard import SchrodingerLicenseTokenGuard 4 | 5 | from tests.tests_paths import PATH_SCHRODINGER_EXAMPLES 6 | from dockstream.utils.files_paths import attach_root_path 7 | 8 | 9 | class Test_Schrodinger_token_guard(unittest.TestCase): 10 | 11 | def test_token_guard_with_file(self): 12 | f = open(attach_root_path(PATH_SCHRODINGER_EXAMPLES.LICADMIN_FILE), 'r') 13 | lines = [line.rstrip("\n") for line in f.readlines()] 14 | f.close() 15 | 16 | # this works, as 144 tokens are available 17 | token_guard = SchrodingerLicenseTokenGuard(token_pools={"GLIDE_SP_DOCKING": 118}) 18 | self.assertTrue(token_guard._check_licstat_output(lines)) 19 | 20 | # this does not work, as only 144 tokens are available 21 | token_guard = SchrodingerLicenseTokenGuard(token_pools={"GLIDE_SP_DOCKING": 145}) 22 | self.assertFalse(token_guard._check_licstat_output(lines)) 23 | 24 | # this does not work, as only 200 tokens are available for GLIDE_XP_DOCKING 25 | token_guard = SchrodingerLicenseTokenGuard(token_pools={"GLIDE_SP_DOCKING": 118, 26 | "GLIDE_XP_DOCKING": 201}) 27 | self.assertFalse(token_guard._check_licstat_output(lines)) 28 | 29 | def test_token_guard_with_execution(self): 30 | # this should work (until no more licenses are available at this point in time) 31 | token_guard = SchrodingerLicenseTokenGuard( 32 | prefix_execution="module load schrodinger/2019-4", 33 | token_pools={"GLIDE_SP_DOCKING": 8}, 34 | wait_interval_seconds=10, 35 | wait_limit_seconds=60 36 | ) 37 | self.assertTrue(token_guard.guard()) 38 | 39 | # this will fail 40 | token_guard = SchrodingerLicenseTokenGuard( 41 | prefix_execution="module load schrodinger/2019-4", 42 | token_pools={"GLIDE_SP_DOCKING": 9000}, 43 | wait_interval_seconds=3, 44 | wait_limit_seconds=10 45 | ) 46 | self.assertFalse(token_guard.guard()) 47 | -------------------------------------------------------------------------------- /tests/TautEnum/__init__.py: -------------------------------------------------------------------------------- 1 | from tests.TautEnum.test_TautEnum_functionality import * 2 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | from tests.test_PDBPreparation import * 2 | from tests.test_ligand_preparation import * 3 | from tests.tests_translation import Test_molecule_container_translation 4 | -------------------------------------------------------------------------------- /tests/ligand/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/tests/ligand/__init__.py -------------------------------------------------------------------------------- /tests/rDock/__init__.py: -------------------------------------------------------------------------------- 1 | from tests.rDock.test_rDock_target_preparation import * 2 | from tests.rDock.test_rDock_backend import * 3 | -------------------------------------------------------------------------------- /tests/test_PDBPreparation.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | import tempfile 4 | 5 | from rdkit import Chem 6 | 7 | from dockstream.core.pdb_preparator import PDBPreparator 8 | from dockstream.containers.target_preparation_container import TargetPreparationContainer 9 | from dockstream.utils.enums.target_preparation_enum import TargetPreparationEnum 10 | from dockstream.utils.general_utils import gen_temp_file 11 | 12 | from tests.tests_paths import PATHS_1UYD 13 | from dockstream.utils.files_paths import attach_root_path 14 | 15 | 16 | class Test_PDBPreparation(unittest.TestCase): 17 | 18 | @classmethod 19 | def setUpClass(cls): 20 | cls._TE = TargetPreparationEnum() 21 | 22 | def setUp(self): 23 | pass 24 | 25 | @classmethod 26 | def tearDownClass(cls): 27 | pass 28 | 29 | def test_fix_good_structure(self): 30 | conf = TargetPreparationContainer({self._TE.TARGETPREP: {self._TE.FIX: {self._TE.FIX_STANDARDIZE: True, 31 | self._TE.FIX_MISSINGHEAVYATOMS: True, 32 | self._TE.FIX_MISSINGLOOPS: True, 33 | self._TE.FIX_ADDWATERBOX: True, 34 | self._TE.FIX_REMOVEHETEROGENS: True, 35 | self._TE.FIX_MISSINGHYDROGENS: False}}}) 36 | input_pdb_file = attach_root_path(PATHS_1UYD.TARGET_APO_PDB) 37 | temp_pdb_output = gen_temp_file(suffix=".pdb") 38 | input_mol = Chem.MolFromPDBFile(input_pdb_file, sanitize=True) 39 | 40 | # first processing: add water box and do not fix hydrogens that are missing 41 | prep = PDBPreparator(conf=conf) 42 | self.assertEqual(input_mol.GetNumAtoms(), 1921) 43 | self.assertEqual(input_mol.GetNumHeavyAtoms(), 1921) 44 | self.assertEqual([input_mol.GetConformer().GetPositions()[1][1], 45 | input_mol.GetConformer().GetPositions()[7][1], 46 | input_mol.GetConformer().GetPositions()[35][1]], 47 | [28.546, 26.816, 21.825]) 48 | prep.fix_pdb(input_pdb_file=input_pdb_file, output_pdb_file=temp_pdb_output) 49 | output_mol = Chem.MolFromPDBFile(temp_pdb_output, sanitize=True) 50 | self.assertEqual(output_mol.GetNumAtoms(), 3835) 51 | self.assertEqual(output_mol.GetNumHeavyAtoms(), 3835) 52 | os.remove(temp_pdb_output) 53 | 54 | # second processing: no water box and but add hydrogens 55 | temp_pdb_output = gen_temp_file(suffix=".pdb") 56 | conf[self._TE.TARGETPREP][self._TE.FIX][self._TE.FIX_ADDWATERBOX] = False 57 | conf[self._TE.TARGETPREP][self._TE.FIX][self._TE.FIX_MISSINGHYDROGENS] = True 58 | prep = PDBPreparator(conf=conf) 59 | prep.fix_pdb(input_pdb_file=input_pdb_file, output_pdb_file=temp_pdb_output) 60 | output_mol = Chem.MolFromPDBFile(temp_pdb_output, sanitize=True, removeHs=False) 61 | self.assertEqual(output_mol.GetNumAtoms(), 4126) 62 | self.assertEqual(output_mol.GetNumHeavyAtoms(), 1922) 63 | os.remove(temp_pdb_output) 64 | 65 | def test_fix_bad_structure(self): 66 | conf = TargetPreparationContainer({self._TE.TARGETPREP: {self._TE.FIX: {self._TE.FIX_STANDARDIZE: True, 67 | self._TE.FIX_MISSINGHEAVYATOMS: True, 68 | self._TE.FIX_MISSINGLOOPS: True, 69 | self._TE.FIX_ADDWATERBOX: False, 70 | self._TE.FIX_REMOVEHETEROGENS: True, 71 | self._TE.FIX_MISSINGHYDROGENS: True}}}) 72 | input_pdb_file = attach_root_path(PATHS_1UYD.LIGAND_MISSING_PARTS_PDB) 73 | temp_pdb_output = gen_temp_file(suffix=".pdb") 74 | input_mol = Chem.MolFromPDBFile(input_pdb_file, sanitize=True) 75 | prep = PDBPreparator(conf=conf) 76 | self.assertEqual(input_mol.GetNumAtoms(), 1892) 77 | self.assertEqual(input_mol.GetNumHeavyAtoms(), 1892) 78 | prep.fix_pdb(input_pdb_file=input_pdb_file, output_pdb_file=temp_pdb_output) 79 | output_mol = Chem.MolFromPDBFile(temp_pdb_output, removeHs=False, proximityBonding=False, sanitize=True) 80 | self.assertEqual(output_mol.GetNumAtoms(), 4533) 81 | self.assertEqual(output_mol.GetNumHeavyAtoms(), 2144) 82 | os.remove(temp_pdb_output) 83 | -------------------------------------------------------------------------------- /tests/test_input_model.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from glob import glob 3 | 4 | from dockstream.core.input_model import AzdockInput 5 | from dockstream.utils.files_paths import attach_root_path 6 | 7 | 8 | class TestAllJsonFilesInExamples(unittest.TestCase): 9 | def test_docking_jsons(self): 10 | files_dir = attach_root_path("examples/docking") 11 | json_files = glob(f"{files_dir}/*.json") 12 | for f in json_files: 13 | with self.subTest(f=f): 14 | inp = AzdockInput.parse_file(f) 15 | self.assertTrue(isinstance(inp, AzdockInput)) 16 | 17 | def test_ligand_jsons(self): 18 | files_dir = attach_root_path("examples/ligand_preparation") 19 | json_files = glob(f"{files_dir}/*.json") 20 | for f in json_files: 21 | with self.subTest(f=f): 22 | inp = AzdockInput.parse_file(f) 23 | self.assertTrue(isinstance(inp, AzdockInput)) 24 | 25 | 26 | if __name__ == '__main__': 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /tests/test_ligand_preparation.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from rdkit import Chem 4 | 5 | from dockstream.core.ligand_preparator import LigandPreparator, Input 6 | from dockstream.utils.enums.ligand_preparation_enum import LigandPreparationEnum 7 | from dockstream.utils.enums.docking_enum import DockingConfigurationEnum 8 | 9 | from tests.tests_paths import PATHS_1UYD 10 | from dockstream.utils.files_paths import attach_root_path 11 | 12 | _LP = LigandPreparationEnum() 13 | _CE = DockingConfigurationEnum() 14 | 15 | 16 | class Test_ligand_preparation(unittest.TestCase): 17 | 18 | def setUp(self): 19 | file = attach_root_path(PATHS_1UYD.LIGANDS_SDF) 20 | mols = [mol for mol in Chem.SDMolSupplier(file) if mol is not None] 21 | self.ligands = mols 22 | 23 | def test_initialization(self): 24 | prep = LigandPreparator( 25 | ligands=self.ligands, 26 | pool_id="testPool", 27 | input=Input() 28 | ) 29 | self.assertEqual(len(prep.get_ligands()), 15) 30 | self.assertEqual(type(prep.get_ligands()), list) 31 | -------------------------------------------------------------------------------- /tests/tests_data/1UYD/LICENSE_CITATION.txt: -------------------------------------------------------------------------------- 1 | Based on 1UYD structure (PDB): http://dx.doi.org/10.1016/j.chembiol.2004.03.033 2 | Ligands (MIT license): http://github.com/Discngine/rdkit_tethered_minimization (Peter Schmidtke) -------------------------------------------------------------------------------- /tests/tests_data/1UYD/PU8.pdb: -------------------------------------------------------------------------------- 1 | HETATM 1647 C19 PU8 A1224 4.403 15.528 26.579 1.00 43.34 C 2 | HETATM 1648 O3 PU8 A1224 5.122 15.084 25.453 1.00 38.5 O 3 | HETATM 1649 C5 PU8 A1224 5.091 13.786 24.846 1.00 38.08 C 4 | HETATM 1650 C6 PU8 A1224 3.959 13.178 24.291 1.00 36.1 C 5 | HETATM 1651 C4 PU8 A1224 6.324 13.153 24.774 1.00 37.95 C 6 | HETATM 1652 O1 PU8 A1224 7.437 13.8 25.363 1.00 41.22 O 7 | HETATM 1653 C7 PU8 A1224 7.968 14.982 24.74 1.00 44.16 C 8 | HETATM 1654 C3 PU8 A1224 6.465 11.928 24.166 1.00 36.97 C 9 | HETATM 1655 O2 PU8 A1224 7.738 11.276 24.146 1.00 36.02 O 10 | HETATM 1656 C8 PU8 A1224 8.125 10.375 23.092 1.00 36.99 C 11 | HETATM 1657 C2 PU8 A1224 5.35 11.326 23.613 1.00 35.51 C 12 | HETATM 1658 C1 PU8 A1224 4.106 11.922 23.656 1.00 35.3 C 13 | HETATM 1659 C9 PU8 A1224 2.981 11.134 22.997 1.00 34.84 C 14 | HETATM 1660 C10 PU8 A1224 1.799 10.898 23.897 1.00 34.9 C 15 | HETATM 1661 N1 PU8 A1224 0.569 11.343 23.665 1.00 31.78 N 16 | HETATM 1662 C11 PU8 A1224 -0.186 10.943 24.666 1.00 32.61 C 17 | HETATM 1663 C13 PU8 A1224 -1.534 11.121 24.945 1.00 30.23 C 18 | HETATM 1664 N5 PU8 A1224 -2.439 11.829 24.033 1.00 30.89 N 19 | HETATM 1665 C12 PU8 A1224 0.625 10.27 25.567 1.00 36.14 C 20 | HETATM 1666 N4 PU8 A1224 0.118 9.78 26.717 1.00 30.6 N 21 | HETATM 1667 C14 PU8 A1224 -1.195 9.985 26.947 1.00 31.1 C 22 | HETATM 1668 N3 PU8 A1224 -2.004 10.644 26.089 1.00 29.53 N 23 | HETATM 1669 N2 PU8 A1224 1.854 10.251 25.056 1.00 37.25 N 24 | HETATM 1670 C15 PU8 A1224 3.053 9.635 25.638 1.00 39.92 C 25 | HETATM 1671 C16 PU8 A1224 2.913 8.131 25.636 1.00 43.4 C 26 | HETATM 1672 C17 PU8 A1224 3.644 7.266 24.612 1.00 47.59 C 27 | HETATM 1673 C18 PU8 A1224 4.665 7.894 23.678 1.00 49.42 C 28 | HETATM 1674 CL PU8 A1224 2.419 14.003 24.367 1.00 31.27 CL 29 | -------------------------------------------------------------------------------- /tests/tests_data/1UYD/ligand_PU8.sdf: -------------------------------------------------------------------------------- 1 | 2 | RDKit 3D 3 | 4 | 28 30 0 0 0 0 0 0 0 0999 V2000 5 | 4.4030 15.5280 26.5790 C 0 0 0 0 0 0 0 0 0 0 0 0 6 | 5.1220 15.0840 25.4530 O 0 0 0 0 0 0 0 0 0 0 0 0 7 | 5.0910 13.7860 24.8460 C 0 0 1 0 0 0 0 0 0 0 0 0 8 | 3.9590 13.1780 24.2910 C 0 0 0 0 0 0 0 0 0 0 0 0 9 | 6.3240 13.1530 24.7740 C 0 0 0 0 0 0 0 0 0 0 0 0 10 | 7.4370 13.8000 25.3630 O 0 0 0 0 0 0 0 0 0 0 0 0 11 | 7.9680 14.9820 24.7400 C 0 0 0 0 0 0 0 0 0 0 0 0 12 | 6.4650 11.9280 24.1660 C 0 0 0 0 0 0 0 0 0 0 0 0 13 | 7.7380 11.2760 24.1460 O 0 0 0 0 0 0 0 0 0 0 0 0 14 | 8.1250 10.3750 23.0920 C 0 0 0 0 0 0 0 0 0 0 0 0 15 | 5.3500 11.3260 23.6130 C 0 0 0 0 0 0 0 0 0 0 0 0 16 | 4.1060 11.9220 23.6560 C 0 0 0 0 0 0 0 0 0 0 0 0 17 | 2.9810 11.1340 22.9970 C 0 0 0 0 0 0 0 0 0 0 0 0 18 | 1.7990 10.8980 23.8970 C 0 0 0 0 0 0 0 0 0 0 0 0 19 | 0.5690 11.3430 23.6650 N 0 0 0 0 0 0 0 0 0 0 0 0 20 | -0.1860 10.9430 24.6660 C 0 0 0 0 0 0 0 0 0 0 0 0 21 | -1.5340 11.1210 24.9450 C 0 0 0 0 0 0 0 0 0 0 0 0 22 | -2.4390 11.8290 24.0330 N 0 0 0 0 0 0 0 0 0 0 0 0 23 | 0.6250 10.2700 25.5670 C 0 0 0 0 0 0 0 0 0 0 0 0 24 | 0.1180 9.7800 26.7170 N 0 0 0 0 0 0 0 0 0 0 0 0 25 | -1.1950 9.9850 26.9470 C 0 0 0 0 0 0 0 0 0 0 0 0 26 | -2.0040 10.6440 26.0890 N 0 0 0 0 0 0 0 0 0 0 0 0 27 | 1.8540 10.2510 25.0560 N 0 0 0 0 0 0 0 0 0 0 0 0 28 | 3.0530 9.6350 25.6380 C 0 0 0 0 0 0 0 0 0 0 0 0 29 | 2.9130 8.1310 25.6360 C 0 0 0 0 0 0 0 0 0 0 0 0 30 | 3.6440 7.2660 24.6120 C 0 0 0 0 0 0 0 0 0 0 0 0 31 | 4.6650 7.8940 23.6780 C 0 0 0 0 0 0 0 0 0 0 0 0 32 | 2.4190 14.0030 24.3670 Cl 0 0 0 0 0 0 0 0 0 0 0 0 33 | 2 1 1 0 34 | 3 2 1 6 35 | 4 3 1 0 36 | 5 3 1 0 37 | 6 5 1 0 38 | 7 6 1 0 39 | 8 5 1 0 40 | 9 8 1 0 41 | 10 9 1 0 42 | 11 8 1 0 43 | 12 11 1 0 44 | 12 4 1 0 45 | 13 12 1 0 46 | 14 13 1 0 47 | 15 14 1 0 48 | 16 15 1 0 49 | 17 16 1 0 50 | 18 17 1 0 51 | 19 16 1 0 52 | 20 19 1 0 53 | 21 20 1 0 54 | 22 21 1 0 55 | 22 17 1 0 56 | 23 19 1 0 57 | 23 14 1 0 58 | 24 23 1 0 59 | 25 24 1 0 60 | 26 25 1 0 61 | 27 26 1 0 62 | 28 4 1 0 63 | M END 64 | $$$$ 65 | -------------------------------------------------------------------------------- /tests/tests_data/1UYD/ligands.csv: -------------------------------------------------------------------------------- 1 | smiles,name 2 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21,test_comp_1 3 | CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21,test_comp_2 4 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)ncnc21,test_comp_3 5 | CCCCn1c(Cc2cccc(OC)c2)nc2c(N)ncnc21,test_comp_4 6 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)nc(F)nc21,new_comp_1 7 | CCCCn1c(Cc2ccc(OC)cc2)nc2c(N)ncnc21,new_comp_2 8 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)ncnc21,new_comp_3 9 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21,new_comp_4 10 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)nc(F)nc21,new_comp_5 11 | C#CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21,other_source 12 | CC(C)NCCCn1c(Cc2cc3c(cc2I)OCO3)nc2c(N)nc(F)nc21,other_source 13 | CC(C)NCCCn1c(Sc2cc3c(cc2Br)OCO3)nc2c(N)ncnc21,other_source 14 | CC(C)NCCCn1c(Sc2cc3c(cc2I)OCO3)nc2c(N)ncnc21,other_source 15 | COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1,other_source 16 | Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12,other_source 17 | Cc1cc(cn1C)c2csc(n2)N=C(N)N,taut_enum_comp1 18 | CC(C)(C)CCC1(c2ccccc2C(=O)C(C1=O)C3=NS(=O)(=O)c4cc(ccc4N3)NS(=O)(=O)C)NCc5cccc(c5)OC,taut_enum_comp2 19 | -------------------------------------------------------------------------------- /tests/tests_data/1UYD/ligands_smiles.txt: -------------------------------------------------------------------------------- 1 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21 2 | CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21 3 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)ncnc21 4 | CCCCn1c(Cc2cccc(OC)c2)nc2c(N)ncnc21 5 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)nc(F)nc21 6 | CCCCn1c(Cc2ccc(OC)cc2)nc2c(N)ncnc21 7 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)ncnc21 8 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 9 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)nc(F)nc21 10 | C#CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 11 | CC(C)NCCCn1c(Cc2cc3c(cc2I)OCO3)nc2c(N)nc(F)nc21 12 | CC(C)NCCCn1c(Sc2cc3c(cc2Br)OCO3)nc2c(N)ncnc21 13 | CC(C)NCCCn1c(Sc2cc3c(cc2I)OCO3)nc2c(N)ncnc21 14 | COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1 15 | Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12 16 | -------------------------------------------------------------------------------- /tests/tests_data/1UYD/ligands_smiles_dup.txt: -------------------------------------------------------------------------------- 1 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21 2 | CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21 3 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)ncnc21 4 | CCCCn1c(Cc2cccc(OC)c2)nc2c(N)ncnc21 5 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)nc(F)nc21 6 | CCCCn1c(Cc2ccc(OC)cc2)nc2c(N)ncnc21 7 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)ncnc21 8 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 9 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)nc(F)nc21 10 | C#CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 11 | CC(C)NCCCn1c(Cc2cc3c(cc2I)OCO3)nc2c(N)nc(F)nc21 12 | CC(C)NCCCn1c(Sc2cc3c(cc2Br)OCO3)nc2c(N)ncnc21 13 | CC(C)NCCCn1c(Sc2cc3c(cc2I)OCO3)nc2c(N)ncnc21 14 | COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1 15 | Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12 16 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21 17 | CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21 18 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)ncnc21 19 | CCCCn1c(Cc2cccc(OC)c2)nc2c(N)ncnc21 20 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)nc(F)nc21 21 | CCCCn1c(Cc2ccc(OC)cc2)nc2c(N)ncnc21 22 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)ncnc21 23 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 24 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)nc(F)nc21 25 | C#CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 26 | CC(C)NCCCn1c(Cc2cc3c(cc2I)OCO3)nc2c(N)nc(F)nc21 27 | CC(C)NCCCn1c(Sc2cc3c(cc2Br)OCO3)nc2c(N)ncnc21 28 | CC(C)NCCCn1c(Sc2cc3c(cc2I)OCO3)nc2c(N)ncnc21 29 | COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1 30 | Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12 31 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21 32 | CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21 33 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)ncnc21 34 | CCCCn1c(Cc2cccc(OC)c2)nc2c(N)ncnc21 35 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)nc(F)nc21 36 | CCCCn1c(Cc2ccc(OC)cc2)nc2c(N)ncnc21 37 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)ncnc21 38 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 39 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)nc(F)nc21 40 | C#CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 41 | CC(C)NCCCn1c(Cc2cc3c(cc2I)OCO3)nc2c(N)nc(F)nc21 42 | CC(C)NCCCn1c(Sc2cc3c(cc2Br)OCO3)nc2c(N)ncnc21 43 | CC(C)NCCCn1c(Sc2cc3c(cc2I)OCO3)nc2c(N)ncnc21 44 | COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1 45 | Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12 46 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21 47 | CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21 48 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)ncnc21 49 | CCCCn1c(Cc2cccc(OC)c2)nc2c(N)ncnc21 50 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)nc(F)nc21 51 | CCCCn1c(Cc2ccc(OC)cc2)nc2c(N)ncnc21 52 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)ncnc21 53 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 54 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)nc(F)nc21 55 | C#CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 56 | CC(C)NCCCn1c(Cc2cc3c(cc2I)OCO3)nc2c(N)nc(F)nc21 57 | CC(C)NCCCn1c(Sc2cc3c(cc2Br)OCO3)nc2c(N)ncnc21 58 | CC(C)NCCCn1c(Sc2cc3c(cc2I)OCO3)nc2c(N)ncnc21 59 | COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1 60 | Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12 61 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21 62 | CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21 63 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)ncnc21 64 | CCCCn1c(Cc2cccc(OC)c2)nc2c(N)ncnc21 65 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)nc(F)nc21 66 | CCCCn1c(Cc2ccc(OC)cc2)nc2c(N)ncnc21 67 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)ncnc21 68 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 69 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)nc(F)nc21 70 | C#CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 71 | CC(C)NCCCn1c(Cc2cc3c(cc2I)OCO3)nc2c(N)nc(F)nc21 72 | CC(C)NCCCn1c(Sc2cc3c(cc2Br)OCO3)nc2c(N)ncnc21 73 | CC(C)NCCCn1c(Sc2cc3c(cc2I)OCO3)nc2c(N)ncnc21 74 | COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1 75 | Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12 76 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21 77 | CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21 78 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)ncnc21 79 | CCCCn1c(Cc2cccc(OC)c2)nc2c(N)ncnc21 80 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)nc(F)nc21 81 | CCCCn1c(Cc2ccc(OC)cc2)nc2c(N)ncnc21 82 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)ncnc21 83 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 84 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)nc(F)nc21 85 | C#CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 86 | CC(C)NCCCn1c(Cc2cc3c(cc2I)OCO3)nc2c(N)nc(F)nc21 87 | CC(C)NCCCn1c(Sc2cc3c(cc2Br)OCO3)nc2c(N)ncnc21 88 | CC(C)NCCCn1c(Sc2cc3c(cc2I)OCO3)nc2c(N)ncnc21 89 | COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1 90 | Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12 91 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21 92 | CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21 93 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)ncnc21 94 | CCCCn1c(Cc2cccc(OC)c2)nc2c(N)ncnc21 95 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)nc(F)nc21 96 | CCCCn1c(Cc2ccc(OC)cc2)nc2c(N)ncnc21 97 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)ncnc21 98 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 99 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)nc(F)nc21 100 | C#CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 101 | CC(C)NCCCn1c(Cc2cc3c(cc2I)OCO3)nc2c(N)nc(F)nc21 102 | CC(C)NCCCn1c(Sc2cc3c(cc2Br)OCO3)nc2c(N)ncnc21 103 | CC(C)NCCCn1c(Sc2cc3c(cc2I)OCO3)nc2c(N)ncnc21 104 | COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1 105 | Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12 106 | -------------------------------------------------------------------------------- /tests/tests_data/1UYD/ligands_smiles_taut_enum.smi: -------------------------------------------------------------------------------- 1 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21 2 | CXXC 3 | CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21 4 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)ncnc21 5 | CCCCn1c(Cc2cccc(OC)c2)nc2c(N)ncnc21 6 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)nc(F)nc21 7 | CCCCn1c(Cc2ccc(OC)cc2)nc2c(N)ncnc21 8 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)ncnc21 9 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 10 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)nc(F)nc21 11 | C#CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21 12 | CC(C)NCCCn1c(Cc2cc3c(cc2I)OCO3)nc2c(N)nc(F)nc21 13 | CC(C)NCCCn1c(Sc2cc3c(cc2Br)OCO3)nc2c(N)ncnc21 14 | CC(C)NCCCn1c(Sc2cc3c(cc2I)OCO3)nc2c(N)ncnc21 15 | COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1 16 | Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12 17 | Cc1cc(cn1C)c2csc(n2)N=C(N)N 18 | CC(C)(C)CCC1(c2ccccc2C(=O)C(C1=O)C3=NS(=O)(=O)c4cc(ccc4N3)NS(=O)(=O)C)NCc5cccc(c5)OC 19 | -------------------------------------------------------------------------------- /tests/tests_data/1UYD/ligands_taut_enum.csv: -------------------------------------------------------------------------------- 1 | smile,name 2 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)ncnc21,amol_1 3 | CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2)nc2c(N)ncnc21,amol_2 4 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)ncnc21,amol_3 5 | CCCCn1c(Cc2cccc(OC)c2)nc2c(N)ncnc21,amol_4 6 | C#CCCCn1c(Cc2cc(OC)c(OC)c(OC)c2Cl)nc2c(N)nc(F)nc21,amol_5 7 | CCCCn1c(Cc2ccc(OC)cc2)nc2c(N)ncnc21,amol_6 8 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)ncnc21,amol_7 9 | CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21,amol_8 10 | CCCCn1c(Cc2ccc3c(c2)OCO3)nc2c(N)nc(F)nc21,amol_9 11 | C#CCCCn1c(Cc2cc(OC)ccc2OC)nc2c(N)nc(F)nc21,amol_10 12 | CC(C)NCCCn1c(Cc2cc3c(cc2I)OCO3)nc2c(N)nc(F)nc21,amol_11 13 | CC(C)NCCCn1c(Sc2cc3c(cc2Br)OCO3)nc2c(N)ncnc21,amol_12 14 | CC(C)NCCCn1c(Sc2cc3c(cc2I)OCO3)nc2c(N)ncnc21,amol_13 15 | COc1ccc(OC)c(Cc2nc3nc(F)nc(N)c3[nH]2)c1,amol_14 16 | Nc1nccn2c(NCc3ccccc3)c(Cc3cc4c(cc3Br)OCO4)nc12,amol_15 17 | Cc1cc(cn1C)c2csc(n2)N=C(N)N,amol_16 18 | CC(C)(C)CCC1(c2ccccc2C(=O)C(C1=O)C3=NS(=O)(=O)c4cc(ccc4N3)NS(=O)(=O)C)NCc5cccc(c5)OC,amol_33 19 | -------------------------------------------------------------------------------- /tests/tests_data/Gold/Gold_binding_site.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/tests/tests_data/Gold/Gold_binding_site.pkl -------------------------------------------------------------------------------- /tests/tests_data/OpenEye/1UYD_reference_receptor.oeb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/tests/tests_data/OpenEye/1UYD_reference_receptor.oeb -------------------------------------------------------------------------------- /tests/tests_data/OpenEyeHybrid/1UYD_reference_receptor.oeb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/tests/tests_data/OpenEyeHybrid/1UYD_reference_receptor.oeb -------------------------------------------------------------------------------- /tests/tests_data/Schrodinger/1UYD_grid.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/tests/tests_data/Schrodinger/1UYD_grid.zip -------------------------------------------------------------------------------- /tests/tests_data/Schrodinger/1UYD_hbond_constraints.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/tests/tests_data/Schrodinger/1UYD_hbond_constraints.zip -------------------------------------------------------------------------------- /tests/tests_data/rDock/rbcavity_1UYD.prm: -------------------------------------------------------------------------------- 1 | RBT_PARAMETER_FILE_V1.00 2 | TITLE rDock_default_cavity_reference_ligand 3 | 4 | RECEPTOR_FILE 5 | RECEPTOR_FLEX 3.0 6 | 7 | ################################################################## 8 | ### CAVITY DEFINITION: REFERENCE LIGAND METHOD 9 | ################################################################## 10 | SECTION MAPPER 11 | SITE_MAPPER RbtLigandSiteMapper 12 | REF_MOL 13 | RADIUS 6.0 14 | SMALL_SPHERE 1.0 15 | MIN_VOLUME 100 16 | MAX_CAVITIES 1 17 | VOL_INCR 0.0 18 | GRIDSTEP 0.5 19 | END_SECTION 20 | 21 | ################################# 22 | #CAVITY RESTRAINT PENALTY 23 | ################################# 24 | SECTION CAVITY 25 | SCORING_FUNCTION RbtCavityGridSF 26 | WEIGHT 1.0 27 | END_SECTION 28 | -------------------------------------------------------------------------------- /tests/tests_data/rDock/rbcavity_1UYD_updated.as: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MolecularAI/DockStream/c62e6abd919b5b54d144f5f792d40663c9a43a5b/tests/tests_data/rDock/rbcavity_1UYD_updated.as -------------------------------------------------------------------------------- /tests/tests_data/rDock/rbcavity_1UYD_updated.prm: -------------------------------------------------------------------------------- 1 | RBT_PARAMETER_FILE_V1.00 2 | TITLE rDock_default_cavity_reference_ligand 3 | 4 | RECEPTOR_FILE /StructureBased/DockStream/tests/tests_data/1UYD/1UYD_apo.mol2 5 | RECEPTOR_FLEX 3.0 6 | 7 | ################################################################## 8 | ### CAVITY DEFINITION: REFERENCE LIGAND METHOD 9 | ################################################################## 10 | SECTION MAPPER 11 | SITE_MAPPER RbtLigandSiteMapper 12 | REF_MOL /StructureBased/DockStream/tests/tests_data/1UYD/ligand_PU8.sdf 13 | RADIUS 6.0 14 | SMALL_SPHERE 1.0 15 | MIN_VOLUME 100 16 | MAX_CAVITIES 1 17 | VOL_INCR 0.0 18 | GRIDSTEP 0.5 19 | END_SECTION 20 | 21 | ################################# 22 | #CAVITY RESTRAINT PENALTY 23 | ################################# 24 | SECTION CAVITY 25 | SCORING_FUNCTION RbtCavityGridSF 26 | WEIGHT 1.0 27 | END_SECTION 28 | -------------------------------------------------------------------------------- /tests/tests_translation.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | 4 | from rdkit import Chem 5 | import openeye.oechem as oechem 6 | 7 | from tests.tests_paths import PATHS_1UYD, MAIN_CONFIG 8 | from dockstream.utils.files_paths import attach_root_path 9 | from dockstream.utils.translations.translation import OpenEyeMolToRDkitMol, RDkitMolToOpenEyeMol 10 | from dockstream.utils.smiles import to_smiles 11 | 12 | 13 | class Test_molecule_container_translation(unittest.TestCase): 14 | 15 | @classmethod 16 | def setUpClass(cls): 17 | if "OE_LICENSE" in MAIN_CONFIG: 18 | os.environ["OE_LICENSE"] = MAIN_CONFIG["OE_LICENSE"] 19 | 20 | def setUp(self): 21 | # read in the molecules in "OpenEye" containers 22 | ifs = oechem.oemolistream() 23 | ifs.SetFormat(oechem.OEFormat_SDF) 24 | ifs.open(attach_root_path(PATHS_1UYD.LIGANDS_SDF)) 25 | 26 | self.ligands_OpenEye = [] 27 | for mol in ifs.GetOEMols(): 28 | # this is critical: make a copy, otherwise empty molecules will populate the list 29 | self.ligands_OpenEye.append(oechem.OEMol(mol)) 30 | 31 | # read in the molecules in "RDkit" format 32 | self.ligands_RDkit = [] 33 | for mol in Chem.SDMolSupplier(attach_root_path(PATHS_1UYD.LIGANDS_SDF)): 34 | if mol is None: 35 | continue 36 | self.ligands_RDkit.append(mol) 37 | 38 | @classmethod 39 | def tearDownClass(cls): 40 | pass 41 | 42 | def test_RDkit2OpenEye(self): 43 | translated_ligands_OpenEye = [] 44 | for mol in self.ligands_RDkit: 45 | translated_ligands_OpenEye.append(RDkitMolToOpenEyeMol(molecule=mol, bySMILES=False)) 46 | self.assertEqual(len(translated_ligands_OpenEye), 15) 47 | 48 | m1_trans = translated_ligands_OpenEye[1] 49 | m1_ori = self.ligands_OpenEye[1] 50 | self.assertEqual([m1_ori.NumAtoms(), 51 | oechem.OECount(m1_ori, oechem.OEIsHeavy()), 52 | oechem.OECount(m1_ori, oechem.OEAtomIsInRing()), 53 | oechem.OECount(m1_ori, oechem.OEIsRotor())], 54 | [m1_trans.NumAtoms(), 55 | oechem.OECount(m1_trans, oechem.OEIsHeavy()), 56 | oechem.OECount(m1_trans, oechem.OEAtomIsInRing()), 57 | oechem.OECount(m1_trans, oechem.OEIsRotor())]) 58 | 59 | def test_OpenEye2RDkit(self): 60 | translated_ligands_RDkit = [] 61 | for mol in self.ligands_OpenEye: 62 | translated_ligands_RDkit.append(OpenEyeMolToRDkitMol(molecule=mol, bySMILES=False)) 63 | self.assertEqual(len(translated_ligands_RDkit), 15) 64 | 65 | m1_trans = translated_ligands_RDkit[1] 66 | m1_ori = self.ligands_RDkit[1] 67 | self.assertEqual([m1_ori.GetNumAtoms(), m1_ori.GetNumHeavyAtoms(), m1_ori.GetNumBonds()], 68 | [m1_trans.GetNumAtoms(), m1_trans.GetNumHeavyAtoms(), m1_trans.GetNumBonds()]) 69 | self.assertEqual(to_smiles(m1_ori), 70 | to_smiles(m1_trans)) 71 | 72 | def test_RDkit2OpenEye_bySMILES(self): 73 | translated_ligands_OpenEye = [] 74 | for mol in self.ligands_RDkit: 75 | translated_ligands_OpenEye.append(RDkitMolToOpenEyeMol(molecule=mol, bySMILES=True)) 76 | self.assertEqual(len(translated_ligands_OpenEye), 15) 77 | 78 | m1_trans = translated_ligands_OpenEye[1] 79 | m1_ori = self.ligands_OpenEye[1] 80 | self.assertEqual([m1_ori.NumAtoms(), 81 | oechem.OECount(m1_ori, oechem.OEIsHeavy()), 82 | oechem.OECount(m1_ori, oechem.OEAtomIsInRing()), 83 | oechem.OECount(m1_ori, oechem.OEIsRotor())], 84 | [m1_trans.NumAtoms(), 85 | oechem.OECount(m1_trans, oechem.OEIsHeavy()), 86 | oechem.OECount(m1_trans, oechem.OEAtomIsInRing()), 87 | oechem.OECount(m1_trans, oechem.OEIsRotor())]) 88 | self.assertEqual(oechem.OEMolToSmiles(m1_ori), 89 | oechem.OEMolToSmiles(m1_trans)) 90 | 91 | def test_OpenEye2RDkit_bySMILES(self): 92 | translated_ligands_RDkit = [] 93 | for mol in self.ligands_OpenEye: 94 | translated_ligands_RDkit.append(OpenEyeMolToRDkitMol(molecule=mol, bySMILES=True)) 95 | self.assertEqual(len(translated_ligands_RDkit), 15) 96 | 97 | m1_trans = translated_ligands_RDkit[1] 98 | m1_ori = self.ligands_RDkit[1] 99 | self.assertEqual([m1_ori.GetNumAtoms(), m1_ori.GetNumHeavyAtoms(), m1_ori.GetNumBonds()], 100 | [m1_trans.GetNumAtoms(), m1_trans.GetNumHeavyAtoms(), m1_trans.GetNumBonds()]) 101 | self.assertEqual(to_smiles(m1_ori), 102 | to_smiles(m1_trans)) 103 | -------------------------------------------------------------------------------- /unit_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | import unittest 5 | from tests import * 6 | from tests.ligand import * 7 | from tests.AutodockVina import * 8 | from tests.RDkit import * 9 | from tests.rDock import * 10 | from tests.Gold import * 11 | from tests.Schrodinger import * 12 | from tests.OpenEye_Hybrid import * 13 | from tests.Corina import * 14 | from tests.TautEnum import * 15 | 16 | if __name__ == '__main__': 17 | unittest.main() 18 | --------------------------------------------------------------------------------