Digital Trials pipeline configured for WES
Source-only snapshot of the cluster branch for WES execution. Large reference files (HPA/MANE/ensemble FASTA, model weights, ~597 MB) are omitted: they are baked into the container images at build time and mounted from the dreamdock-data PVC at runtime, and exceed the Gitea request size limit. Pipeline entry point is main.nf, which orchestrates the biotransformer, conplex and tissue modules as a single workflow. Ligand inputs are read from the eureka workspace; protein_zarr and chembl_db come from the dreamdock-data PVC.
This commit is contained in:
144
nf_metabol_screen_adaptive/app/screen.py
Normal file
144
nf_metabol_screen_adaptive/app/screen.py
Normal file
@@ -0,0 +1,144 @@
|
||||
# Custom Rust modules
|
||||
import mol_fingerprint as mf
|
||||
import bitexpand
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from pathlib import Path
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import zarr
|
||||
from zarr.storage import LocalStore
|
||||
from zarr.codecs import ZstdCodec
|
||||
|
||||
from sklearn.preprocessing import normalize
|
||||
from parallelbar import progress_map
|
||||
|
||||
import onnxruntime as ort
|
||||
print('CUDA available:', 'CUDAExecutionProvider' in ort.get_available_providers())
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("-i","--input-tsv", type=Path, required=True, help="Input TSV file with molecules to screen. It must not have any labels and has only two columns, 1st molecule_label, 2nd molecule_smiles")
|
||||
parser.add_argument("-z","--zarr-protein", type=Path, required=True, help="Input Zarr DB that holds the protein ids and their normalized projection vectors")
|
||||
return parser
|
||||
|
||||
parser = parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
path_metabolites : Path = args.input_tsv
|
||||
if not path_metabolites.is_file():
|
||||
raise ValueError(f"{path_metabolites} IS MISSING OR NOT A FILE")
|
||||
|
||||
df_metabolite = pd.read_csv(
|
||||
path_metabolites,
|
||||
sep="\t",
|
||||
header=None,
|
||||
names=["smiles" ,"compound_id"]
|
||||
)
|
||||
|
||||
path_zarr = args.zarr_protein
|
||||
store_zarr = LocalStore(path_zarr, read_only=True)
|
||||
group_zarr = zarr.open(store_zarr, mode="r")
|
||||
protein_vecs = (group_zarr["normalized"][:])
|
||||
|
||||
|
||||
path_onnx = Path("/app/drug_projector.onnx")
|
||||
|
||||
def load_model(model_path):
|
||||
"""Load ONNX model with GPU support"""
|
||||
model_path = Path(model_path)
|
||||
|
||||
# Set up providers for GPU execution
|
||||
# providers = ['CUDAExecutionProvider', 'CPUExecutionProvider']
|
||||
providers = ['CPUExecutionProvider']
|
||||
|
||||
# Create inference session
|
||||
session = ort.InferenceSession(str(model_path), providers=providers)
|
||||
|
||||
# Verify GPU is being used
|
||||
print(f"Available providers: {session.get_providers()}")
|
||||
|
||||
return session
|
||||
|
||||
session = load_model(path_onnx)
|
||||
|
||||
def run_inference(input_vector):
|
||||
"""Run inference on the model"""
|
||||
# Get input/output names
|
||||
input_name = session.get_inputs()[0].name
|
||||
output_name = session.get_outputs()[0].name
|
||||
|
||||
# Run inference
|
||||
outputs = session.run([output_name], {input_name: input_vector})
|
||||
|
||||
return outputs[0]
|
||||
|
||||
def normalize_vectors_sklearn(vectors):
|
||||
"""Normalize using sklearn - often fastest for large arrays"""
|
||||
return normalize(vectors, norm='l2', axis=1)
|
||||
|
||||
def project_drugs(smiles : list[str]) -> np.ndarray :
|
||||
fps = bitexpand.expand_bits(np.array([
|
||||
np.frombuffer(fp,dtype=np.uint8)
|
||||
for fp in mf.generate_fingerprints(smiles)
|
||||
]))
|
||||
return normalize_vectors_sklearn(run_inference(fps))
|
||||
|
||||
pvecs = project_drugs(df_metabolite["smiles"].values.tolist())
|
||||
|
||||
my_results = np.dot(protein_vecs, pvecs.T)
|
||||
|
||||
pids = group_zarr["ids"][:]
|
||||
|
||||
# Create output zarr store
|
||||
path_outdir = Path("./")
|
||||
zarr_name = path_zarr.stem + "_results.zarr"
|
||||
path_output_zarr = path_outdir / zarr_name
|
||||
|
||||
# Create zarr store
|
||||
store_output = LocalStore(path_output_zarr, read_only=False)
|
||||
group_output = zarr.open(store_output, mode="w")
|
||||
|
||||
out_compress =[
|
||||
ZstdCodec( level=13 )
|
||||
]
|
||||
|
||||
# Store the data
|
||||
# Similarity matrix: (n_proteins, n_compounds)
|
||||
z1 = group_output.create_array(
|
||||
"scores",
|
||||
dtype="float32",
|
||||
shape=my_results.shape,
|
||||
chunks=(min(1000, my_results.shape[0]), my_results.shape[1]),
|
||||
compressors=out_compress
|
||||
)
|
||||
z1[:] = my_results
|
||||
|
||||
# Compound IDs
|
||||
z2 = group_output.create_array(
|
||||
"compound_ids",
|
||||
dtype="str",
|
||||
shape=(len(df_metabolite),),
|
||||
compressors=out_compress
|
||||
)
|
||||
z2[:] = df_metabolite["compound_id"].values
|
||||
|
||||
# Protein IDs
|
||||
z3 = group_output.create_array(
|
||||
"protein_ids",
|
||||
dtype="str",
|
||||
shape=(len(pids),),
|
||||
compressors=out_compress
|
||||
)
|
||||
z3[:] = pids
|
||||
|
||||
# Store metadata
|
||||
group_output.attrs['n_proteins'] = my_results.shape[0]
|
||||
group_output.attrs['n_compounds'] = my_results.shape[1]
|
||||
group_output.attrs['source_zarr'] = str(path_zarr)
|
||||
|
||||
print(f"Results saved to {path_output_zarr}")
|
||||
print(f"Shape: {my_results.shape[0]} proteins x {my_results.shape[1]} compounds")
|
||||
print("PROCESS COMPLETED SUCCESSFULLY")
|
||||
Reference in New Issue
Block a user