Python API

You can import the configuration classes, PocketVinaGPU, P2RankProcessor and Results directly from pocketvina.

Configuration and runs

class pocketvina.main.PocketVinaConfig(database_path: str | None = None, protein_paths: str | None = None, protein_list: str | None = None, smiles_file: str | None = None, output_dir: str | None = None, batch_size: int | None = None, p2rank_config: P2RankConfig | None = None, pocket_config: PocketConfig = <factory>, output_format: str = 'files', tmp_dir: str | None = None, top_pockets: int | None = None, pockets: int | Sequence[int] | str | None = None, pockets_dir: str | None = None, seed: int | None = 42, num_modes: int | None = None, energy_range: float | None = None, ligand_prep: str = 'standard', gzip_level: int = 6, posebusters: bool = False, posebusters_workers: int | None = None, ligands_per_call: int | None = None, engine_timeout: float | None = None, gpus: str | None = None, procs_per_gpu: int | str = 'auto', vram_per_proc_mib: int = 6600)[source]

Settings of a docking run. Only smiles_file and protein_paths (or database_path with protein_list) are required.

  • protein_paths: text file with one protein structure per line (.pdb, .cif or .pdbqt, may be gzipped).

  • smiles_file: CSV file with the header molecule_name,smiles and one ligand per line (.csv or .txt).

  • output_dir: folder the results are written to (default "output").

  • output_format: "files" (PDBQT files and combined_results.csv, as in v0.1) or "atlas" (tables, resumable).

  • batch_size: molecules per docking batch (default 10; "atlas": 1000 per engine call, see ligands_per_call).

  • p2rank_config: how P2Rank finds the pockets, a P2RankConfig (default P2RankConfig()).

  • pocket_config: docking box size and GPU threads, a PocketConfig (default PocketConfig()).

  • top_pockets: dock only the N best-ranked pockets of each protein (default all; htvs_mode=True: 5).

  • pockets: dock only these P2Rank ranks: 10, [10, 11, 12], range(10, 13) or "10-12" (not with top_pockets or htvs_mode).

  • pockets_dir: "atlas" only: a folder of P2Rank predictions, <protein file name>.csv, e.g. from P2RankProcessor (its <output_dir>/proteins/pockets): proteins with one there are docked into those pockets, P2Rank is not run.

  • seed: random seed; the same seed gives the same results (default 42; None: random).

Advanced:

  • database_path, protein_list: dock the proteins of a prepared database folder instead of protein_paths.

  • tmp_dir: folder for temp files (default $POCKETVINA_TMPDIR, $SLURM_TMPDIR, $TMPDIR, the system temp folder).

  • num_modes, energy_range: poses kept per ligand and pocket, and their score range (default 20 within 20 kcal/mol).

  • ligand_prep: "standard" (largest fragment, seeded 3D) or "legacy" (as before v0.2, to regenerate old results).

  • gzip_level: compression level of the "atlas" pose files (-1 to 9, default 6).

  • posebusters: "atlas" only: check the best pose of each ligand with PoseBusters while docking (default False).

  • posebusters_workers: processes for the PoseBusters checks (default the CPUs available, at most 16).

  • ligands_per_call: "atlas" only: ligands per engine call (default batch_size if set, else 1000; 0: all at once).

  • engine_timeout: seconds one engine call may take; a slower call is stopped (default no limit).

  • gpus: "atlas" only: the GPU to dock on, an nvidia-smi index or UUID (default the first visible one, e.g. the one SLURM gives the job); "all" or "0,2" for several (usually one job per GPU is simpler).

  • procs_per_gpu: "atlas" only: pockets docked at the same time on the GPU, a number or "auto" (default: as many as its free memory holds at vram_per_proc_mib each, e.g. 3 on a 24 GB P40, 5 on a 40 GB A100).

  • vram_per_proc_mib: GPU memory one engine needs, in MiB, for procs_per_gpu (default 6600).

class pocketvina.main.P2RankConfig(threads: int = 4, visualizations: bool = False, vis_copy_proteins: bool = False, output_dir: str = 'output', model: str = 'alphafold_conservation_hmm')[source]

How P2Rank finds the pockets of each protein.

P2Rank is described in the "P2Rank: machine learning based tool for rapid and accurate prediction of ligand binding sites from protein structure" paper.

class pocketvina.main.PocketConfig(size_x: int = 20, size_y: int = 20, size_z: int = 20, thread: int = 8000)[source]

The docking box around each pocket centre, and the GPU threads per docking.

class pocketvina.main.PocketVinaGPU(config: PocketVinaConfig, htvs_mode=False)[source]

Docking with PocketVina, from the "PocketVina Enables Scalable and Highly Accurate Physically Valid Docking through Multi-Pocket Conditioning" paper.

P2Rank finds the pockets of each protein ("P2Rank: machine learning based tool for rapid and accurate prediction of ligand binding sites from protein structure") and every ligand is docked into the best pockets on the GPU, with an engine based on QuickVina2-GPU 2.1 ("Vina-GPU 2.1: towards further optimizing docking speed and precision of AutoDock Vina and its derivatives") and AutoDock Vina ("AutoDock Vina: improving the speed and accuracy of docking with a new scoring function, efficient optimization, and multithreading").

execute_docking() → str | None[source]

Main docking execution with better error handling

With output_format="atlas" this is pipeline.run_atlas and returns the results directory; at the end it shows the best scores of the run's proteins (best_scores(), at most BEST_SCORES_SHOWN rows): a table in a notebook, else printed.

results()[source]

The results in output_dir (a pocketvina.io.results.Results), also of an earlier session: PocketVinaGPU(config).results(). Needs output_format="atlas".

best_scores(protein=None, top: int | None = None) → pandas.DataFrame[source]

Best (lowest) Vina score of each protein x ligand, best first; see Results.best_scores.

protein

a protein id (the file name without extension), e.g. "1fbl", or a list, e.g. ["1fbl", "2W83"];

None (default): all proteins.

top

only the first N rows, e.g. 10; None (default): all rows.

select(protein: str, ligand, pocket=None, mode=1)[source]

One protein x ligand pair, to show, check or save; see Results.select: pair = pocketvina.select(protein="1fbl", ligand="molecule1"), then pair.show(), pair.bust(), pair.export("1fbl_molecule1.sdf").

protein

a protein id as in best_scores(), e.g. "1fbl".

ligand

a ligand id (its name in the SMILES file) as in best_scores(), e.g. "molecule1".

pocket

a pocket number, e.g. 2; None (default): the pocket of the pair's best pose; "all": every pocket the ligand was docked into.

mode

1 (default): the best mode of the pocket; 2, 3, ...: that mode; "all": every mode of the pocket(s).

show(protein=None, *, path=None, molstar: str = 'inline', theme: str = 'auto', height: int = 760, max_ligands: int | None = 100)[source]

The results as on the PocketVina Atlas website's protein page (3D view, Top hits, Selected pair, Pockets); in a notebook below the cell, elsewhere an HTML file whose path is returned. See Results.show.

protein

a protein id, e.g. "1fbl", or a list of them; None (default): all proteins.

path

write the page to this HTML file instead, e.g. "results.html".

molstar

"inline" (default, works offline) or "url" (the 3D viewer's code from the PocketVina Atlas website).

theme

"auto" (default), "light" or "dark".

height

height of the view in a notebook, in pixels, e.g. 900.

max_ligands

ligands per protein in the page (best first), e.g. 50; None: all.

class pocketvina.main.P2RankProcessor(config: P2RankConfig = None)[source]

Runs P2Rank on a list of proteins and saves their pockets, for docking later.

P2Rank is described in the "P2Rank: machine learning based tool for rapid and accurate prediction of ligand binding sites from protein structure" paper.

process_file_list(file_list_path: str | Sequence[str]) → Dict[str, bool][source]

Process multiple PDB files from a list file (or a list of paths)

PocketVinaGPU(config, htvs_mode=True) docks the 5 best-ranked pockets of each protein if top_pockets is not set. After execute_docking(), failed_proteins maps each protein that could not be docked to the reason.

pocketvina.pipeline.run_atlas(pv, force: bool = False) → str[source]

Dock every protein of pv (a PocketVinaGPU or a PocketVinaConfig) into the atlas results directory config.output_dir and return its path.

Proteins already committed there are skipped. A protein that fails (missing file, P2Rank error, every engine run failed or timed out) is logged, left out and retried by the next run; the ids are in pv.failed_proteins. An engine call that fails or takes longer than config.engine_timeout while other calls of the protein work leaves its ligands as engine_error runs of the committed protein. A results directory that holds a run with other settings or ligands raises ValueError unless force=True (proteins done stay done, unless the ligand list changed: see ResultsDir.init_run). The engine calls run on the slots of plan_engine_slots (config gpus, procs_per_gpu, vram_per_proc_mib), several at a time when there are several slots; they are not run parameters, so a run may be resumed with others. All temp files live in one folder from config.tmp_dir (see io.writer.resolve_tmp_dir), removed at the end, also when the run is stopped with Ctrl-C or SIGTERM (engine.exit_on_sigterm; the running engines are killed). With config.posebusters, every protein committed (or found done) is handed to a background process that runs bust.bust_results on it while docking goes on; the run waits for it at the end. A protein whose checks did not finish (the run was stopped) is checked when the run is resumed.

pocketvina.pipeline.plan_engine_slots(config: PocketVinaConfig) → List[str | None][source]

CUDA_VISIBLE_DEVICES of each engine slot of an atlas run: gpu.plan_slots over the GPUs that config.gpus names (None: the first visible GPU; "all": every one) with config.procs_per_gpu (default "auto": as many as the GPU's free memory holds) and config.vram_per_proc_mib.

Without a GPU list (no nvidia-smi, e.g. in a container with the driver's OpenCL library only, or a CUDA_VISIBLE_DEVICES whose GPUs gpu.visible_gpus cannot match) the engines use the environment's default GPU (the first of NVIDIA's OpenCL platform): procs_per_gpu slots (1 for "auto") of value None. ValueError if config.gpus names a GPU that is not visible, or is set while nvidia-smi lists none.

Results

Results reads a results folder (Results format). It sees only the proteins that are done.

class pocketvina.io.results.Results(path)[source]

A results directory written by pipeline.run_atlas or io.importer.import_legacy.

protein arguments are protein ids; ligand arguments a ligand_id (str) or a ligand_idx (int); pocket a P2Rank rank (1-based); mode 1-based. Unknown proteins, ligands and missing poses raise KeyError. Pose files are kept open (at most MAX_OPEN_POSE_FILES); use as a context manager or call close().

close()[source]

Close the open pose files (they are reopened when needed).

manifest(protein: str | None = None) → dict[source]

MANIFEST.json of the run, or manifest/<protein>.json of one protein.

proteins() → List[str][source]

Ids of the committed proteins, sorted.

table(name: str, protein: str | Iterable[str] | None = None, columns: List[str] | None = None) → pandas.DataFrame[source]

Table name (one of TABLES, or another folder under tables/) as one DataFrame, for one protein id, a list of them or (None) all committed proteins, in protein order.

pairs(protein: str | Iterable[str] | None = None, columns: List[str] | None = None) → pandas.DataFrame[source]

Best pose per protein x ligand: the pairs table, then pb_valid (only when there are PoseBusters results, see posebusters) and ligand_efficiency (-vina / n_heavy, heavy atoms of the docked fragment; NaN without a pose). pb_status / pb_valid are those of the PoseBusters row of the best pose (same pocket and mode), if any. columns may name these derived columns too.

best_scores(protein: str | Iterable[str] | None = None, top: int | None = None) → pandas.DataFrame[source]

Best (lowest) Vina score of each protein x ligand, best first: one row per docked pair with protein_id, ligand_id, vina (kcal/mol), best_pocket, best_mode, ligand_efficiency (-vina / heavy atoms); no PoseBusters columns, also when PoseBusters ran (see posebusters()). Ligands without a pose are left out.

protein

a protein id (the file name without extension), e.g. "1fbl", or a list, e.g. ["1fbl", "2W83"];

None (default): all proteins.

top

only the first N rows, e.g. 10; None (default): all rows.

select(protein: str, ligand, pocket=None, mode=1)[source]

One protein x ligand pair, to show, check or save (a pocketvina.selection.Selection): pair = results.select("1fbl", "molecule1"), then pair.show(), pair.bust(), pair.export().

protein

a protein id as in best_scores(), e.g. "1fbl".

ligand

a ligand id (its name in the SMILES file) as in best_scores(), e.g. "molecule1".

pocket

a pocket number, e.g. 2; None (default): the pocket of the pair's best pose; "all": every pocket the ligand was docked into.

mode

1 (default): the best mode of the pocket; 2, 3, ...: that mode; "all": every mode of the pocket(s).

show(protein=None, *, path=None, molstar: str = 'inline', theme: str = 'auto', height: int = 760, max_ligands: int | None = 100)[source]

The results as on the PocketVina Atlas website's protein page: the 3D view (pocket chips, modes, legend, contacts, Save image) beside the tabs Top hits (pick a ligand there), Selected pair and Pockets, with a protein menu when there are several proteins. In Jupyter, Colab or VSCode it is shown below the cell; elsewhere an HTML file is written (open it in a browser) and its path returned.

protein

a protein id, e.g. "1fbl", or a list of them; None (default): all proteins.

path

write the page to this HTML file instead, e.g. "results.html"; returns the path.

molstar

"inline" (default): the 3D viewer's code is in the page (works offline); "url": loaded from the PocketVina Atlas website when the page opens (a much smaller page; needs internet).

theme

"auto" (default: as the browser), "light" or "dark".

height

height of the view in a notebook, in pixels, e.g. 900.

max_ligands

ligands per protein in the page (best first), e.g. 50; None: all (a large page for a large run).

posebusters(protein: str | Iterable[str] | None = None, columns: List[str] | None = None) → pandas.DataFrame[source]

PoseBusters results (tables.POSEBUSTERS, written by pocketvina.bust.bust_results) of one protein, a list or all committed proteins; empty if there are none. Results of a protein docked again since it was checked are left out. Bit b of pb_mask / pb_na_mask is check posebusters_checks(protein)[b].

posebusters_checks(protein: str) → List[str][source]

Names of the PoseBusters checks in the mask bits of a protein's results (bust.check_names).

duckdb()[source]

In-memory DuckDB connection with the views ligands, proteins, pockets, pocket_runs, modes, pairs over the Parquet files of the committed proteins (as they are now: reconnect to see proteins committed later), and posebusters when there are PoseBusters results (see posebusters).

The pairs view has the columns of pairs(): the pairs table with pb_status / pb_valid of the PoseBusters row of the best pose (same pocket and mode; pb_valid is NULL without one, also when there are no PoseBusters results) and ligand_efficiency (-vina / n_heavy, NULL if n_heavy is unknown).

ligand_idx(ligand) → int[source]

ligand_idx of a ligand_id (str) or a ligand_idx (int, checked).

pose_block(protein: str, ligand, pocket: int) → str[source]

The engine output (all MODELs) of a ligand in a pocket, byte for byte as the engine wrote it.

pose_model(protein: str, ligand, pocket: int, mode: int) → str[source]

One MODEL (MODEL ... ENDMDL) of the engine output; IndexError if there is no such mode.

top_sdf(protein: str, ligand) → str | None[source]

SDF of the ligand's best pose in the protein (section A), or None if there is none.

structure_path(protein: str) → str[source]

Path of the stored input structure (structures/<protein_id>.pdb.gz, .pdbqt.gz, ...).

structure(protein: str) → bytes[source]

The input structure (PDB, mmCIF or PDBQT text), decompressed.

to_combined_csv(path, protein: str | Iterable[str] | None = None) → str[source]

Write every mode as a row of the legacy combined_results.csv (COMBINED_COLUMNS; protein is <protein_id>-pocket<k>, molecule_name the ligand_id); returns the path. Rows are in protein, pocket, ligand_idx, mode order; scores are written as the engine printed them.

export(out_dir, what: str = 'best', fmt: str = 'sdf', protein: str | Iterable[str] | None = None) → List[str][source]

Write poses or tables as plain files under out_dir; returns the paths written.

  • fmt="sdf": what="best" the stored best pose per protein x ligand (<protein_id>/<protein_id>-pocket<k>-<ligand>_best.sdf); what="all" every mode of every engine output converted with pocketvina.convert (needs the docked SMILES; <protein_id>/<protein_id>-pocket<k>-<ligand>_out.sdf, modes that do not convert are left out).

  • fmt="pdbqt": the best MODEL (..._best.pdbqt), or every engine output as written (..._out.pdbqt).

  • fmt="csv": best_poses.csv (the pairs table), or combined_results.csv (to_combined_csv).

pocketvina.io.importer.import_legacy(output_dir: str, results_dir: str, smiles_file: str | None = None, *, tmp_dir: str | None = None, gzip_level: int = 6, force: bool = False) → str[source]

Convert a legacy PocketVina output_dir into the atlas layout in results_dir; returns its path.

One protein per proteins/structures/<receptor>.pdbqt; engine outputs of other receptors are skipped with a warning. Ligands are numbered in the order of smiles_file (molecule_name,smiles; ligands of the run that it lacks follow), else by name. The docked pockets are those with an engine output or config; a ligand without output in one of them gets a "no_output" run, a ligand of smiles_file that the legacy run never prepared a "skipped" one. Section A holds the best pose of each ligand as SDF (pocketvina.convert) when its SMILES is known; without SMILES it stays empty and sdf_status is "convert_failed". Box sizes come from configs/ when kept, else they are NaN. Docked pockets ranked above 127 do not fit the int8 pocket columns: they are left out with a warning and noted in the proteins table.

Importing into a results directory that holds this import already resumes it (proteins done are skipped). force=True replaces another run definition there and imports every protein again.

Selections

class pocketvina.selection.Selection(*, results_dir: str, protein: str, ligand: str, ligand_idx: int, smiles: str, smiles_docked: str, pocket: None | int | str, mode: int | str, best_pocket: int, best_mode: int, vina: float, docked_pockets: List[int], poses: List[Pose], top_sdf: str | None)[source]

Poses of one protein x ligand pair, picked with select (Results.select, PocketVinaGPU.select).

Attributes: protein, ligand (ids), smiles, pocket and mode (as selected), vina (the pair's best Vina score, kcal/mol), best_pocket / best_mode (where that pose is), poses (a table: pocket, mode, vina, rmsd_lb, rmsd_ub), name (the file name stem, e.g. PV_1fbl_molecule1_top).

property poses: pandas.DataFrame

The selected poses: pocket, mode, vina (kcal/mol), rmsd_lb, rmsd_ub (A, to mode 1 of the pocket).

property name: str

File name stem of the selection (Atlas IDs with "PV_"): PV_<protein>_<ligand>_top (the best pose), ..._pk2_m03 (one pose), ..._pk2_modes (all modes of a pocket), ..._pocketall_top (the best pose of each pocket), ..._pocketall_modes, ..._pocketall_m03.

show(path=None, *, molstar: str = 'inline', theme: str = 'auto', height: int = 760, max_ligands: int = 100)[source]

The PocketVina Atlas website's protein page for this pair's protein, with this pair selected: the 3D view (pocket chips, modes, legend, contacts, Save image) beside the tabs Top hits, Selected pair and Pockets.

In Jupyter, Colab or VSCode it is shown below the cell; elsewhere an HTML file is written (open it in a browser) and its path returned. Everything is in the page: it works offline and in a saved notebook.

path

write the page to this HTML file instead, e.g. "pair.html"; returns the path.

molstar

"inline" (default): the 3D viewer's code is in the page (about 1 MB); "url": loaded from the PocketVina Atlas website when the page opens (needs internet, a much smaller page).

theme

"auto" (default: as the browser), "light" or "dark".

height

height of the view in a notebook, in pixels, e.g. 900.

max_ligands

ligands listed in Top hits, best first, e.g. 50 (default 100).

The 3D view is drawn with Mol*, described in the "Mol* Viewer: modern web app for 3D visualization and analysis of large biomolecular structures" paper.

bust(workers: int | None = None) → pandas.DataFrame[source]

PoseBusters (config "dock") on the selected poses against the protein; nothing is written to disk and the stored results do not change. Returns one row per pose: pocket, mode, vina, pb_valid (True: every check passed), pb_status ("valid", "invalid", or why it was not checked: "convert_failed", "timeout", "error"), failed_checks, then one column per PoseBusters check (True: passed, False: failed, empty: not applicable).

workers

processes that run the checks at the same time, e.g. 4; None (default): one per pose, at most the CPUs this process may use.

PoseBusters is described in the "PoseBusters: AI-based docking methods fail to generate physically valid poses or generalise to novel sequences" paper.

export(path=None, fmt: str = 'sdf') → str[source]

Write the selected poses into one file; returns its path.

path

the file, e.g. "1fbl_molecule1.sdf", or a folder; None (default): <name>.<fmt> in the working folder, e.g. PV_1fbl_molecule1_top.sdf.

fmt

"sdf" (default): one record per pose (converted from the docked model with the ligand's SMILES), with the protein, ligand, pocket, mode and Vina score (affinity, kcal/mol) as properties; "pdbqt": the docked models as the engine wrote them, one MODEL per pose.

PoseBusters

PoseBusters checks of the docked poses in a results directory: bust_results, check_names.

Per protein, the poses to check are picked from the results (select): the stored best pose of every ligand (section A SDF), or the best modes overall or per pocket, converted from the engine output with pocketvina.convert. The protein structure (structures/<protein_id>.*.gz) is decompressed in memory; PDBQT and mmCIF structures are converted to PDB text first, since PoseBusters reads only PDB proteins, and crystal waters (HOH) are left out as for docking (other HETATM records, e.g. metal ions and cofactors, stay). Worker processes load the protein once each, exactly as PoseBusters loads a .pdb file (same loader options of the config), and check one pose at a time, so that a pose which takes too long can be stopped: it is tried again with the next of timeouts in a fresh worker, and recorded as "timeout" after the last one. Every selected pose gets a row in tables/posebusters/<protein_id>.parquet (io.tables.POSEBUSTERS), written atomically once the protein is done. The workers share the CPUs this process may use (PoseBusters' internal energy check would otherwise start a thread per core of the machine in each of them).

PoseBusters (pip install posebusters) is an optional dependency, imported only when checks run. Workers are forked on Linux; elsewhere they are spawned, which re-imports the calling script: guard it with if __name__ == "__main__": there.

PoseBusters is described in the "PoseBusters: AI-based docking methods fail to generate physically valid poses or generalise to novel sequences" paper.

pocketvina.bust.require_posebusters() → str[source]

The PoseBusters version; ImportError if it is not installed.

pocketvina.bust.check_names(config='dock') → List[str][source]

Names of the PoseBusters checks of config in mask bit order: bit b of pb_mask / pb_na_mask is check check_names(config)[b]. The same names as the columns of PoseBusters(config).bust(...).

pocketvina.bust.default_workers() → int[source]

Worker processes when workers=None: the CPUs this process may use, at most MAX_DEFAULT_WORKERS.

pocketvina.bust.bust_results(results_dir, *, select: str = 'best', top_k: int = 1, config='dock', workers: int | None = None, timeouts=(30, 300), proteins: str | Sequence[str] | None = None, overwrite: bool = False, tmp_dir: str | None = None) → List[str][source]

Run PoseBusters on the docked poses of a results directory; returns the ids of the proteins checked.

select: "best" the stored best pose of each ligand; "top_k" the top_k best modes of each ligand over all pockets; "per_pocket" the top_k best modes of each ligand in each pocket. Modes other than the stored best pose are converted from the engine output with pocketvina.convert (a failure is a "convert_failed" row). config: a PoseBusters config name ("dock", "dock_fast", ...) or dict. workers: worker processes (None: default_workers()). timeouts: seconds per pose for each attempt; a pose still running after the last one is a "timeout" row (None: no limit). proteins: protein ids (None: every committed protein). A protein that already has a table is skipped unless overwrite (or it was docked again since). Temp files go to io.writer.resolve_tmp_dir(tmp_dir) and are removed at the end.

Rows (io.tables.POSEBUSTERS): pb_status "valid" (no check failed), "invalid", "timeout", "error", "convert_failed" or "no_pose" (pocket and mode are -1 when there is no pose at all); bit b of pb_mask is set if check check_names(config)[b] passed, of pb_na_mask if it gave no result (all bits for poses that were not checked). The check names are also in the Parquet schema metadata (pocketvina.pb_checks).

Visualisation

3D views of docked poses for notebooks (Mol* through MolViewSpec, or py3Dmol) and a table of the best pairs.

from pocketvina import viz
viz.table("results")                                   # best pose per protein x ligand, best first
viz.show("results", "AF-P00533-F1-model_v4", "gefitinib")          # best pose (the stored SDF)
viz.show("results", "AF-P00533-F1-model_v4", "gefitinib", pocket=2, mode=3)
viz.show_modes("results", "AF-P00533-F1-model_v4", "gefitinib", pocket=2)
viz.to_html("results", "AF-P00533-F1-model_v4", "gefitinib", path="pose.html")   # a file to share

The scene follows the PocketVina Atlas viewer (light theme): grey cartoon, the residues within pocket_radius A of the pose as thin ball-and-stick with grey carbons under a faint surface in the pocket's colour, the pose as ball-and-stick with gold carbons, coloured by element, hydrogens hidden, the camera on the pose (+ 8 A), and a label with protein, ligand, pocket, mode and affinity.

Backends: "molstar" needs molviewspec (Python >= 3.10), "py3dmol" needs py3Dmol; "auto" takes Mol* when molviewspec imports, else py3Dmol. Both are optional and imported only when a view is made.

Offline: the views hold the structures, but not the viewers' JavaScript. Mol* loads it from a CDN (jsDelivr) when the view is drawn; without internet use backend="py3dmol" -- py3Dmol also needs its 3Dmol.js, from a CDN by default, but a small script that the browser often has cached. to_html writes a standalone page (structures embedded) to share; it, too, loads the viewer's JavaScript when opened.

Mol* version: MOLSTAR_VERSION (5.5.0: released with molviewspec 1.8.1, it reads the scenes molviewspec 1.8 writes), not molviewspec's default "latest", so a view draws the same way later. To use another one, pass molstar_version= (e.g. "latest") or set $POCKETVINA_MOLSTAR_VERSION (also for pocketvina show).

Mol* is described in the "Mol* Viewer: modern web app for 3D visualization and analysis of large biomolecular structures" paper, MolViewSpec in the "Describing and Sharing Molecular Visualizations Using the MolViewSpec Toolkit" paper and 3Dmol.js in the "3Dmol.js: molecular visualization with WebGL" paper.

pocketvina.viz.show(results: str | PathLike[str] | Results, protein: str, ligand, pocket: int | None = None, mode: int = 1, *, backend: str = 'auto', width=950, height=600, pocket_radius: float = 5.0, surface: bool = True, molstar_version: str | None = None)[source]

3D view of a ligand's pose in a protein; the notebook draws it when it is the cell's result.

results: a results directory (path) or io.results.Results; ligand: ligand_id or ligand_idx. pocket=None: the best pose (the stored SDF of section A; the raw PDBQT model if there is none); else mode mode of that pocket (P2Rank rank), converted to SDF in memory (convert.pose_to_sdf) or, if that fails, the raw PDBQT model. Residues within pocket_radius A of the pose are drawn as sticks (and a faint surface if surface).

backend: "molstar" returns a MolstarView (a MolViewSpec scene with data={"protein.pdb": ..., "ligand.sdf": ...}, shown with molviewspec.molstar_notebook), "py3dmol" a py3Dmol.view, "auto" Mol* when molviewspec imports, else py3Dmol. Outside a notebook the object is returned without drawing anything. Mol* loads its JavaScript from a CDN: version molstar_version (None: $POCKETVINA_MOLSTAR_VERSION, else MOLSTAR_VERSION, 5.5.0; any molstar npm version or tag, e.g. "latest"); without internet use backend="py3dmol" (py3Dmol also needs its 3Dmol.js, from a CDN by default). To share a view, see to_html.

Unknown proteins, ligands, pockets or modes, and ligands without a pose, raise KeyError.

pocketvina.viz.show_modes(results: str | PathLike[str] | Results, protein: str, ligand, pocket: int | None, *, backend: str = 'auto', width=950, height=600, pocket_radius: float = 5.0, surface: bool = True, molstar_version: str | None = None, ui: str = 'stories')[source]

All modes of a ligand in one pocket (pocket=None: the pocket of its best pose).

Mol*: one MolViewSpec snapshot per mode (residues near that mode, the mode table in the description), in the MVS Stories page (ui="stories", with previous/next buttons) or the plain viewer (ui="viewer", Mol*'s snapshot controls). py3Dmol: the modes as frames of one model, animated (residues near any mode). Each mode is converted to SDF in memory, else drawn from its PDBQT model (py3Dmol: if any mode does not convert, all frames are the PDBQT models). See show for the arguments and the offline note.

pocketvina.viz.to_html(results: str | PathLike[str] | Results, protein: str, ligand, pocket: int | None = None, mode: int = 1, path=None, *, backend: str = 'auto', width=950, height=600, pocket_radius: float = 5.0, surface: bool = True, molstar_version: str | None = None) → str[source]

Standalone HTML page of the show view (structures embedded); written to path if given.

Mol*: molviewspec.molstar_html (the scene and its files as a base64 MVSX archive); py3Dmol: its full-page HTML. The page loads the viewer's JavaScript from a CDN when opened, so it needs internet to draw.

pocketvina.viz.table(results: str | PathLike[str] | Results, top: int | None = 50, protein=None) → pandas.DataFrame[source]

Best pose per protein x ligand, best (lowest) Vina score first; top=None for all rows.

Columns: protein_id, ligand_id, smiles_docked, vina, best_pocket, best_mode, ligand_efficiency (-vina / n_heavy of the docked fragment), and pb_status / pb_valid when PoseBusters results are there. Ligands without a pose are left out. protein: one protein id or a list (default: all).

class pocketvina.viz.MolstarView(state, data: Dict[str, bytes], *, info: dict, width=950, height=600, ui: str = 'viewer', molstar_version: str | None = None)[source]

A MolViewSpec scene (state) and the files it loads by name (data), drawn by Mol*.

The result of show/show_modes with the Mol* backend: Jupyter and Colab draw it when it is a cell's result (through molviewspec.molstar_notebook); to_html() gives a standalone page, save(path) writes it. info holds what is shown (protein, ligand, pocket, mode(s), affinity, residues, files).

state_json(indent: int | None = None) → str[source]

The MolViewSpec state (MVSJ text).

to_html() → str[source]

Standalone HTML page: the state and its files as an MVSX archive (base64), Mol* molstar_version from the CDN.

save(path) → str[source]

Write to_html() to path; returns the absolute path.

display() → None[source]

Show the view in Jupyter / Colab now (molviewspec.molstar_notebook).

GPUs

GPUs for the docking engine: the NVIDIA GPUs this process may use (list_gpus) and how many engine processes run on each of them at the same time (plan_slots).

Each engine process ("slot") is pinned to one GPU through its own CUDA_VISIBLE_DEVICES, which NVIDIA's OpenCL honours like CUDA does. One engine at the default thread=8000 holds about 6.4 GB of GPU memory (measured on a Tesla P40; more threads need more), hence DEFAULT_VRAM_PER_PROC_MIB = 6600 MiB. Several engines on one GPU share its compute units: that pays off when one engine leaves the GPU partly idle (e.g. during the CPU-side work of each call), which depends on the GPU and the workload.

Standard library only (nvidia-smi for the GPU list), so the "files" output format still docks without pyarrow.

class pocketvina.gpu.GPU(index: int, uuid: str, name: str, memory_total_mib: int | None, memory_free_mib: int | None)[source]

One GPU as nvidia-smi reports it; the memory fields are None when it reports none ([N/A]).

index: int

Alias for field number 0

uuid: str

Alias for field number 1

name: str

Alias for field number 2

memory_total_mib: int | None

Alias for field number 3

memory_free_mib: int | None

Alias for field number 4

pocketvina.gpu.list_gpus() → List[GPU][source]

The NVIDIA GPUs this process may use: nvidia-smi filtered by $CUDA_VISIBLE_DEVICES (see visible_gpus; $CUDA_DEVICE_ORDER tells how it numbers them). [] without nvidia-smi or when it fails (e.g. a container with the driver's OpenCL library but not nvidia-smi: the engine then uses the first GPU of NVIDIA's OpenCL platform; it docks on NVIDIA GPUs only).

pocketvina.gpu.select_gpus(gpus: Sequence[GPU], spec: str | None) → List[GPU][source]

The GPUs that spec (check_gpu_spec) names, in its order: None the first of gpus (one GPU per run, e.g. the one SLURM gives the job), "all" all of them; ValueError if it names one that is not in gpus (not visible) or the same GPU twice.

pocketvina.gpu.fitting_procs(gpu: GPU, vram_per_proc_mib: int, margin_mib: int = 1024) → int | None[source]

Engine processes of vram_per_proc_mib that fit in the GPU's free memory less margin_mib (at least 1); None when nvidia-smi reports no free memory figure.

pocketvina.gpu.plan_slots(gpus: Sequence[GPU], procs_per_gpu: int | str = 1, vram_per_proc_mib: int = 6600, margin_mib: int = 1024) → List[str][source]

One entry per engine slot, the CUDA_VISIBLE_DEVICES value of its engine (device_id: the GPU's UUID).

procs_per_gpu an int: that many slots per GPU, but no more than its free memory holds at vram_per_proc_mib each (keeping margin_mib free; always at least 1). "auto": as many as fit (fitting_procs; 1 when nvidia-smi reports no free memory). Slots alternate between the GPUs ([g0, g1, g0, g1, ...]), so that fewer tasks than slots still spread over all GPUs. [] for no GPUs.

P2Rank and the engine

P2Rank, the pocket predictor PocketVina docks into: where it is installed, a one-time download of the release PocketVina is tested with, and the Java it needs.

p2rank_home() is the first P2Rank folder (one with a prank launcher) of

  1. $P2RANK_HOME,

  2. the folder of the prank on PATH (P2Rank's launcher, or a link or wrapper script to it; symlinks resolved; not a compiled prank without P2Rank's bin/p2rank.jar next to it, such as the PRANK sequence aligner that bioconda and Debian install under that name),

  3. pocketvina/p2rank_2.5/ in the package directory (source installs before v0.2 unpacked it there),

  4. the user cache ~/.cache/pocketvina/p2rank-2.5.1/ ($XDG_CACHE_HOME instead of ~/.cache when set).

ensure_p2rank() returns the prank launcher of that folder and, if there is none, downloads the official P2Rank 2.5.1 release once (checked against its pinned sha256) and unpacks it into the user cache; the folder appears complete or not at all, and processes starting at the same time (e.g. SLURM array jobs) download it only once. pocketvina setup p2rank does the same ahead of a run, e.g. on a login node that has internet access. Nothing is ever written into the package directory.

P2Rank needs Java 17 or later: its launcher runs $JAVA_HOME/bin/java when JAVA_HOME is set, else java on PATH. check_java() finds that Java the same way and explains how to install one.

Standard library only (tqdm draws the download progress bar when asked to).

P2Rank is described in the "P2Rank: machine learning based tool for rapid and accurate prediction of ligand binding sites from protein structure" paper.

exception pocketvina.p2rank.P2RankError[source]

P2Rank is not installed and cannot be installed here (no network, a bad archive, a full disk...).

exception pocketvina.p2rank.JavaError[source]

No Java, or one older than P2Rank needs.

pocketvina.p2rank.find_p2rank() → P2RankInstall | None[source]

The first P2Rank of $P2RANK_HOME, prank on PATH, the package folder p2rank_2.5/ and the user cache (see the module docstring); None if there is none. A $P2RANK_HOME without a prank is skipped with a warning, a prank on PATH that is not P2Rank (e.g. the PRANK aligner) silently.

pocketvina.p2rank.p2rank_home() → str | None[source]

The folder of the P2Rank PocketVina runs (see find_p2rank), or None if there is none.

pocketvina.p2rank.ensure_p2rank(download: bool = True, *, root=None, archive=None, force: bool = False, progress: bool = False) → str[source]

The prank launcher of the P2Rank to run, installing P2Rank 2.5.1 first if there is none.

Without root, archive and force the P2Rank of find_p2rank() is used if there is one. Otherwise P2Rank goes to <root>/p2rank-2.5.1 (root default: cache_root()), unless it is there already (and not force): unpacked from archive (a p2rank_2.5.1.tar.gz downloaded elsewhere) or, with download, downloaded from P2RANK_URL; either must match P2RANK_SHA256. progress shows a download progress bar (tqdm, on stderr). Raises P2RankError with what to do instead if P2Rank is missing and cannot be installed. A P2Rank installed into another root is found by later runs only through $P2RANK_HOME.

pocketvina.p2rank.check_java(minimum: int = 17) → int[source]

The major version of the Java P2Rank would run; JavaError saying how to get one if it is missing or older than minimum.

pocketvina.engine.engine_path() → str[source]

The engine executable: $POCKETVINA_ENGINE (a path, or a command on PATH), else the package binary pocketvina/PocketVina-GPU, else pocketvina-engine on PATH or in <sys.prefix>/bin (a conda env used without activating it, e.g. as a Jupyter kernel). If there is none, the package binary's path (run_engine reports it missing).

pocketvina.engine.kernel_cache_dir([visible_devices])[source]

Folder for the compiled OpenCL kernels (the config's opencl_binary_path); the engine creates it.

$POCKETVINA_KERNEL_CACHE if set, else ~/.cache/pocketvina/kernels/<key> ($XDG_CACHE_HOME instead of ~/.cache when set; the system temp dir if there is no usable home), where <key> is kernel_cache_key(visible_devices): the folder for an engine run with CUDA_VISIBLE_DEVICES=visible_devices (None: unset), by default with this process's.

pocketvina.engine.resolve_tmp_dir(explicit: str | None = None) → str[source]

A fresh private temp folder (mkdtemp(prefix="pocketvina_")) inside the first of explicit, $POCKETVINA_TMPDIR, $SLURM_TMPDIR, $TMPDIR, tempfile.gettempdir().

explicit is created if needed; an environment variable naming a missing or read-only folder is skipped. The path returned is absolute. The caller removes the folder when done.