Skill Tracer
Skills › Scientific Agent Skills › diffdock › workflows_examples.md

workflows_examples.md

111 lines · skills/diffdock/references/workflows_examples.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# DiffDock workflow recipes
2
3These target v1.1.3 user-complex inference. Input generation and local helper tests
4were executed with synthetic fixtures; pretrained docking and external GNINA/GUI
5commands were source-checked, not executed. Replace illustrative filenames with
6prepared inputs. Run upstream commands from its repository root.
7

DiffDock workflow recipes

These target v1.1.3 user-complex inference. Input generation and local helper tests were executed with synthetic fixtures; pretrained docking and external GNINA/GUI commands were source-checked, not executed. Replace illustrative filenames with prepared inputs. Run upstream commands from its repository root.

Raw lines 1 to 7
8## Generate a traceable screening batch
9
10This Python recipe expects a CSV with `compound_id,smiles`, unique IDs, and a prepared
11`target_protein.pdb`. It preserves source identifiers instead of relabeling filtered
12rows. Generated names must pass the helper's safe-name rule. Screening here produces
13poses for later assessment, not a validated affinity ranking.
15```python
16import csv
17from pathlib import Path
18import pandas as pd
20library = Path("ligand_library.csv")
21with library.open(newline="") as handle:
22 header = next(csv.reader(handle))
23if len(header) != len(set(header)):
24 raise ValueError("Duplicate library columns")
25ligands = pd.read_csv(library, dtype=str, keep_default_na=False)
26if ligands.empty or ligands["compound_id"].eq("").any() or ligands["compound_id"].duplicated().any():
27 raise ValueError("Require nonempty library and unique nonempty compound IDs")
28rows = pd.DataFrame({
29 "complex_name": "compound_" + ligands["compound_id"],
30 "protein_path": str(Path("target_protein.pdb").resolve()),
31 "ligand_description": ligands["smiles"],
32 "protein_sequence": "",
33})
34rows.to_csv("screening.csv", index=False)
35```
37```bash
38python /path/to/diffdock-skill/scripts/prepare_batch_csv.py screening.csv --validate
39python -m inference --config default_inference_args.yaml \
40 --protein_ligand_csv screening.csv --out_dir results/screening_001/ --loglevel INFO
41python /path/to/diffdock-skill/scripts/analyze_results.py results/screening_001/ --export all_poses.csv
42```
44Reconcile every `complex_name` with output directories and expected ranks. A missing
45output is a failed/skipped result, not a nonbinder. Preserve input CSV, configuration,
46checkpoint identity, source revision, logs, and raw outputs together.

Generate a traceable screening batch

This Python recipe expects a CSV with compound_id,smiles, unique IDs, and a prepared target_protein.pdb. It preserves source identifiers instead of relabeling filtered rows. Generated names must pass the helper's safe-name rule. Screening here produces poses for later assessment, not a validated affinity ranking.

import csv
from pathlib import Path
import pandas as pd

library = Path("ligand_library.csv")
with library.open(newline="") as handle:
    header = next(csv.reader(handle))
if len(header) != len(set(header)):
    raise ValueError("Duplicate library columns")
ligands = pd.read_csv(library, dtype=str, keep_default_na=False)
if ligands.empty or ligands["compound_id"].eq("").any() or ligands["compound_id"].duplicated().any():
    raise ValueError("Require nonempty library and unique nonempty compound IDs")
rows = pd.DataFrame({
    "complex_name": "compound_" + ligands["compound_id"],
    "protein_path": str(Path("target_protein.pdb").resolve()),
    "ligand_description": ligands["smiles"],
    "protein_sequence": "",
})
rows.to_csv("screening.csv", index=False)
python /path/to/diffdock-skill/scripts/prepare_batch_csv.py screening.csv --validate
python -m inference --config default_inference_args.yaml \
  --protein_ligand_csv screening.csv --out_dir results/screening_001/ --loglevel INFO
python /path/to/diffdock-skill/scripts/analyze_results.py results/screening_001/ --export all_poses.csv

Reconcile every complex_name with output directories and expected ranks. A missing output is a failed/skipped result, not a nonbinder. Preserve input CSV, configuration, checkpoint identity, source revision, logs, and raw outputs together.

Raw lines 8 to 47
Runs code python /path/to/diffdock-skill/scripts/prepare_batch_csv.py :38
Runs code python /path/to/diffdock-skill/scripts/analyze_results.py :41
48## Receptor ensemble
50Use one row per known conformation, retaining the same ligand state. This illustrative
51input generator does not perform protein preparation:
53```python
54from pathlib import Path
55import pandas as pd
57conformations = ["conf1.pdb", "conf2.pdb", "conf3.pdb"]
58pd.DataFrame({
59 "complex_name": [f"ensemble_{i}" for i in range(len(conformations))],
60 "protein_path": [str(Path(name).resolve()) for name in conformations],
61 "ligand_description": ["CC(=O)Oc1ccccc1C(=O)O"] * len(conformations),
62 "protein_sequence": [""] * len(conformations),
63}).to_csv("ensemble.csv", index=False)
64```
66Copy the bundled config and edit `samples_per_complex` to 20 if increased sampling is
67justified. The YAML value wins over CLI values. Run with the copied config, ensemble
68CSV and a fresh output directory. Inspect all conformations; score differences are
69not relative binding free energies.

Receptor ensemble

Use one row per known conformation, retaining the same ligand state. This illustrative input generator does not perform protein preparation:

from pathlib import Path
import pandas as pd

conformations = ["conf1.pdb", "conf2.pdb", "conf3.pdb"]
pd.DataFrame({
    "complex_name": [f"ensemble_{i}" for i in range(len(conformations))],
    "protein_path": [str(Path(name).resolve()) for name in conformations],
    "ligand_description": ["CC(=O)Oc1ccccc1C(=O)O"] * len(conformations),
    "protein_sequence": [""] * len(conformations),
}).to_csv("ensemble.csv", index=False)

Copy the bundled config and edit samples_per_complex to 20 if increased sampling is justified. The YAML value wins over CLI values. Run with the copied config, ensemble CSV and a fresh output directory. Inspect all conformations; score differences are not relative binding free energies.

Raw lines 48 to 70
71## GNINA as a separate step
73The [official GNINA CLI](https://github.com/gnina/gnina) supports receptor/ligand input
74and `--score_only`. This illustrative loop scores existing poses without relaxation:
76```bash
77for pose in results/screening_001/compound_001/rank*_confidence*.sdf; do
78 test -f "$pose" || continue
79 gnina --receptor target_protein.pdb --ligand "$pose" --score_only > "${pose%.sdf}_gnina.txt"
80done
81```
83Keep different score fields, units, versions and model identities separate. An affinity
84model's output is an estimate requiring appropriate validation; confidence is not its
85substitute. `score_only` does not relax a pose. For subsequent minimization, preserve
86raw coordinates and ligand stereochemistry, specify a compatible protein/ligand force
87field and protonation model, and recheck the result.
89A generic OpenMM `ForceField('amber14-all.xml', ...)` does not parameterize an arbitrary
90ligand. A valid minimization workflow must add the ligand topology/coordinates, obtain
91its parameters, build the combined system, set positions in the Context, and validate
92atom mapping/units before minimization. No incomplete OpenMM snippet is supplied here.

GNINA as a separate step

The official GNINA CLI supports receptor/ligand input and --score_only. This illustrative loop scores existing poses without relaxation:

for pose in results/screening_001/compound_001/rank*_confidence*.sdf; do
    test -f "$pose" || continue
    gnina --receptor target_protein.pdb --ligand "$pose" --score_only > "${pose%.sdf}_gnina.txt"
done

Keep different score fields, units, versions and model identities separate. An affinity model's output is an estimate requiring appropriate validation; confidence is not its substitute. score_only does not relax a pose. For subsequent minimization, preserve raw coordinates and ligand stereochemistry, specify a compatible protein/ligand force field and protonation model, and recheck the result.

A generic OpenMM ForceField('amber14-all.xml', ...) does not parameterize an arbitrary ligand. A valid minimization workflow must add the ligand topology/coordinates, obtain its parameters, build the combined system, set positions in the Context, and validate atom mapping/units before minimization. No incomplete OpenMM snippet is supplied here.

Raw lines 71 to 93
94## Local GUI
96```bash
97python app/main.py
98```
100Upstream documents `http://localhost:7860`. The released interface takes a PDB ID or
101uploaded receptor and ligand SMILES/file; sequence input is supported by inference CLI,
102not this GUI. The application may download a structure given a PDB ID, so record the
103retrieved structure and its biological interpretation. Hosted demo operations and
104network transfer of private inputs require the user's intended destination.

Local GUI

python app/main.py

Upstream documents http://localhost:7860. The released interface takes a PDB ID or uploaded receptor and ligand SMILES/file; sequence input is supported by inference CLI, not this GUI. The application may download a structure given a PDB ID, so record the retrieved structure and its biological interpretation. Hosted demo operations and network transfer of private inputs require the user's intended destination.

Raw lines 94 to 105
Runs code python app/main.py :97
106## Sources
108- [Inference and configuration](https://github.com/gcorso/DiffDock/blob/v1.1.3/inference.py)
109- [Released web interface](https://github.com/gcorso/DiffDock/blob/v1.1.3/app/main.py)
110- [GNINA CLI reference](https://github.com/gnina/gnina)
111- [OpenMM application guide](https://docs.openmm.org/latest/userguide/application/02_running_sims.html)