{ "cells": [ { "cell_type": "markdown", "id": "eebd8987", "metadata": {}, "source": [ "# TMol How-To Guide\n", "\n", "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/RosettaCommons/tmol/blob/main/docs/tutorial/01_tmol_how_to_guide.ipynb)" ] }, { "cell_type": "markdown", "id": "7cb870c8", "metadata": {}, "source": [ "A single, growing reference notebook for working with TMol. Each section is self-contained and can be run independently once the Setup cell below has run." ] }, { "cell_type": "markdown", "id": "56c086b3", "metadata": {}, "source": [ "## 1. Basics" ] }, { "cell_type": "markdown", "id": "f6748a5f", "metadata": {}, "source": [ "Load a structure from the RCSB, inspect it, change it, save it, and build batches of poses." ] }, { "cell_type": "markdown", "id": "540f0927", "metadata": {}, "source": [ "### Setup\n", "\n" ] }, { "cell_type": "markdown", "id": "afcacc4e", "metadata": {}, "source": [ "In Colab, choose a GPU runtime and Run all. For local execution, follow the [installation guide](../installation.md). This section fetches structures live from the RCSB, so no local fixture files are required.\n", "\n", "The first call into any of TMol's native routines in a fresh environment JIT-compiles kernels and can take several minutes; later calls reuse the compiled cache and are fast.\n", "\n", "Wheel install, imports, seeding, and device selection are not themselves part of what this notebook teaches, so they live in [notebook_setup.py](https://github.com/RosettaCommons/tmol/blob/main/docs/tutorial/notebook_setup.py) and are pulled in with a single call." ] }, { "cell_type": "code", "execution_count": 1, "id": "761537e5", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:01.326965Z", "iopub.status.busy": "2026-10-20T00:48:01.326766Z", "iopub.status.idle": "2026-10-20T00:48:08.181239Z", "shell.execute_reply": "2026-10-20T00:48:08.180364Z" }, "tags": [ "collapse-code" ] }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Environment variable CCD_MIRROR_PATH not set. Will not be able to use function requiring this variable. To set it you may:\n", " (1) add the line 'export VAR_NAME=path/to/variable' to your .bashrc or .zshrc file\n", " (2) set it in your current shell with 'export VAR_NAME=path/to/variable'\n", " (3) write it to a .env file in the root of the atomworks.io repository\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "Environment variable PDB_MIRROR_PATH not set. Will not be able to use function requiring this variable. To set it you may:\n", " (1) add the line 'export VAR_NAME=path/to/variable' to your .bashrc or .zshrc file\n", " (2) set it in your current shell with 'export VAR_NAME=path/to/variable'\n", " (3) write it to a .env file in the root of the atomworks.io repository\n" ] } ], "source": [ "try:\n", " import google.colab # noqa: F401\n", "except ImportError:\n", " IN_COLAB = False\n", "else:\n", " IN_COLAB = True\n", "\n", "if IN_COLAB:\n", " from urllib.request import urlretrieve\n", "\n", " urlretrieve(\n", " \"https://raw.githubusercontent.com/RosettaCommons/tmol/\"\n", " \"main/docs/tutorial/notebook_setup.py\",\n", " \"notebook_setup.py\",\n", " )\n", "\n", "from notebook_setup import * # noqa: F401,F403\n", "\n", "device, param_db = setup()\n" ] }, { "cell_type": "markdown", "id": "51164af6", "metadata": {}, "source": [ "### Loading Structures" ] }, { "cell_type": "markdown", "id": "ae944fe5", "metadata": {}, "source": [ "#### Download a CIF file from RCSB" ] }, { "cell_type": "markdown", "id": "83653afc", "metadata": {}, "source": [ "We use [1UBQ](https://www.rcsb.org/structure/1UBQ) (ubiquitin) as the example structure for this section. `fetch_cif` downloads the raw mmCIF text; it is not written to disk here, just held in memory." ] }, { "cell_type": "code", "execution_count": 2, "id": "1e267bf3", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:08.183536Z", "iopub.status.busy": "2026-10-20T00:48:08.183079Z", "iopub.status.idle": "2026-10-20T00:48:08.263722Z", "shell.execute_reply": "2026-10-20T00:48:08.263044Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "downloaded 1UBQ\n" ] } ], "source": [ "PDB_ID = \"1UBQ\"\n", "ubq_cif_text = fetch_cif(PDB_ID)\n", "print(f\"downloaded {PDB_ID}\")" ] }, { "cell_type": "markdown", "id": "34994ac0", "metadata": {}, "source": [ "#### Load a PoseStack from a CIF" ] }, { "cell_type": "markdown", "id": "58a7615c", "metadata": {}, "source": [ "A PoseStack represents a batch of molecular systems (in this case, just a single structure - ubiquitin). PoseStacks are optimized for compactness for efficient processing on the GPU. `pose_stack_from_file` accepts a path or an in-memory buffer." ] }, { "cell_type": "code", "execution_count": 3, "id": "f0baf263", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:08.265905Z", "iopub.status.busy": "2026-10-20T00:48:08.265750Z", "iopub.status.idle": "2026-10-20T00:48:12.629505Z", "shell.execute_reply": "2026-10-20T00:48:12.628795Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n_poses=1, max_n_blocks=76\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n" ] }, { "data": { "application/3dmoljs_load.v0": "
\n

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n
\n", "text/html": [ "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "pose_stack = pose_stack_from_file(io.StringIO(ubq_cif_text), device)\n", "print(f\"n_poses={pose_stack.n_poses}, max_n_blocks={pose_stack.max_n_blocks}\")\n", "\n", "viewer = tmol.view(pose_stack)\n", "viewer.show()\n" ] }, { "cell_type": "markdown", "id": "e3cefc1f", "metadata": {}, "source": [ "#### Load a PoseStack with ligands" ] }, { "cell_type": "markdown", "id": "d0f043be", "metadata": {}, "source": [ "To load a PoseStack with ligands, you must specify `prepare_ligands=True` while loading the structure. Without this flag, any ligands will be silently ommitted from the resulting PoseStack. More details about this in section 4 (TODO: add a forward link/reference to the ligand section when we re-combine the notebooks)." ] }, { "cell_type": "code", "execution_count": 4, "id": "800ad451", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:12.631936Z", "iopub.status.busy": "2026-10-20T00:48:12.631691Z", "iopub.status.idle": "2026-10-20T00:48:14.593819Z", "shell.execute_reply": "2026-10-20T00:48:14.593196Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "==============================\n", "*** Open Babel Warning in WriteMolecule\n", " No 2D or 3D coordinates exist. Stereochemical information will be stored using an Open Babel extension. To generate 2D or 3D coordinates instead use --gen2D or --gen3D.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/home/runner/work/tmol/tmol/tmol/io/_pose_stack_from_biotite.py:1401: UserWarning: Renumbering chain A of the output AtomArray: biotite's CIF writer does not support numbering that decreases within a chain\n", " warnings.warn(\n", "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n" ] }, { "data": { "application/3dmoljs_load.v0": "
\n

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n
\n", "text/html": [ "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Fetch a new PDB with ligands present\n", "LIGAND_PDB_ID = \"3PTB\"\n", "ligand_cif_text = fetch_cif(LIGAND_PDB_ID)\n", "\n", "# Load the PDB with prepare_ligands=True\n", "ligand_pose_stack = pose_stack_from_file(io.StringIO(ligand_cif_text), device, prepare_ligands=True)\n", "ligand_atom_mask = res_mask_to_coord_mask(ligand_pose_stack, tmol.get_ligand_mask(ligand_pose_stack))\n", "viewer = tmol.view(ligand_pose_stack, highlighted=ligand_atom_mask[ligand_pose_stack.real_atoms])\n", "viewer.show()\n" ] }, { "cell_type": "markdown", "id": "cb63673a", "metadata": {}, "source": [ "#### Stacking PoseStacks" ] }, { "cell_type": "markdown", "id": "80429931", "metadata": {}, "source": [ "`tmol` is optimized to work best on batches of structures. \n", "\n", "You can batch multiple structures into a single PoseStack, even if they are different structures." ] }, { "cell_type": "code", "execution_count": 5, "id": "26d67b67", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:14.599406Z", "iopub.status.busy": "2026-10-20T00:48:14.599225Z", "iopub.status.idle": "2026-10-20T00:48:14.617262Z", "shell.execute_reply": "2026-10-20T00:48:14.616524Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n_poses=2, max_n_blocks=225 (members had 76 and 225 blocks)\n" ] } ], "source": [ "multi_pdb_stack = PoseStackBuilder.from_poses([pose_stack, ligand_pose_stack], device)\n", "print(\n", " f\"n_poses={multi_pdb_stack.n_poses}, \"\n", " f\"max_n_blocks={multi_pdb_stack.max_n_blocks} \"\n", " f\"(members had {pose_stack.max_n_blocks} and {ligand_pose_stack.max_n_blocks} blocks)\"\n", ")\n" ] }, { "cell_type": "markdown", "id": "1a690dbd", "metadata": {}, "source": [ "#### Stacking multiple copies of a Pose" ] }, { "cell_type": "markdown", "id": "ff0221e0", "metadata": {}, "source": [ "The same function, given `[pose_stack] * n`, builds a batch of `n` independent copies. This is the standard way to collect several independent stochastic outcomes from one starting structure, such as running FastRelax or the packer several times with different random seeds." ] }, { "cell_type": "code", "execution_count": 6, "id": "3e14858c", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:14.619208Z", "iopub.status.busy": "2026-10-20T00:48:14.619023Z", "iopub.status.idle": "2026-10-20T00:48:14.625894Z", "shell.execute_reply": "2026-10-20T00:48:14.625116Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n_poses=4, max_n_blocks=76\n" ] } ], "source": [ "n_copies = 4\n", "repeat_stack = PoseStackBuilder.from_poses([pose_stack] * n_copies, device)\n", "print(f\"n_poses={repeat_stack.n_poses}, max_n_blocks={repeat_stack.max_n_blocks}\")\n" ] }, { "cell_type": "markdown", "id": "be9789b9", "metadata": {}, "source": [ "### Query the PoseStack for info" ] }, { "cell_type": "markdown", "id": "2f45eb38", "metadata": {}, "source": [ "#### Get all sequences" ] }, { "cell_type": "code", "execution_count": 7, "id": "ae4eb61c", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:14.627972Z", "iopub.status.busy": "2026-10-20T00:48:14.627770Z", "iopub.status.idle": "2026-10-20T00:48:14.630796Z", "shell.execute_reply": "2026-10-20T00:48:14.630117Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "MQIFVKTLTGKTITLEVEPSDTIENVKAKIQDKEGIPPDQQRLIFAGKQLEDGRTLSDYNIQKESTLHLVLRLRGG\n" ] } ], "source": [ "sequence = tmol.get_sequence(pose_stack)\n", "print(sequence)" ] }, { "cell_type": "markdown", "id": "0ca9a345", "metadata": {}, "source": [ "#### Get ligands (3-letter code + SMILES)" ] }, { "cell_type": "markdown", "id": "18c3f773", "metadata": {}, "source": [ "`tmol.get_ligand_mask` flags every ligand (or other non-polymer residue, such as an ion) block in a PoseStack. `tmol.ligand.smiles_from_pose_stack` then derives a canonical SMILES string for one of those residues directly from the PoseStack's own coordinates and connectivity." ] }, { "cell_type": "code", "execution_count": 8, "id": "9137f4c3", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:14.633620Z", "iopub.status.busy": "2026-10-20T00:48:14.633126Z", "iopub.status.idle": "2026-10-20T00:48:16.097935Z", "shell.execute_reply": "2026-10-20T00:48:16.097274Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CA: block 223, SMILES=[Ca-2]\n", "BEN: block 224, SMILES=NC(=[NH2+])c1ccccc1\n" ] } ], "source": [ "ligand_cif_text = fetch_cif(\"3PTB\")\n", "ligand_pose_stack = pose_stack_from_file(\n", " io.StringIO(ligand_cif_text), device, param_db=param_db, prepare_ligands=True\n", ")\n", "\n", "ligand_mask = tmol.get_ligand_mask(ligand_pose_stack)\n", "for block in torch.nonzero(ligand_mask[0]).flatten().tolist():\n", " code = ligand_pose_stack.block_type(0, block).name3\n", " smiles = smiles_from_pose_stack(ligand_pose_stack, 0, block)\n", " print(f\"{code}: block {block}, SMILES={smiles}\")\n" ] }, { "cell_type": "markdown", "id": "cd1aee6f", "metadata": {}, "source": [ "#### Query phi/psi angles using pdb_info" ] }, { "cell_type": "markdown", "id": "bac89877", "metadata": {}, "source": [ "TODO - should phi/psi (and other named-torsion queries) support looking a residue up by its original PDB numbering directly, instead of resolving a block index as a separate step first?" ] }, { "cell_type": "code", "execution_count": 9, "id": "a4ab07fa", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:16.099723Z", "iopub.status.busy": "2026-10-20T00:48:16.099330Z", "iopub.status.idle": "2026-10-20T00:48:16.105975Z", "shell.execute_reply": "2026-10-20T00:48:16.105152Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "chain A residue 43 -> block 42 (LEU)\n", "available torsions: ['phi', 'psi', 'omega', 'chi1', 'chi2']\n", "phi=-103.6 deg, psi=130.2 deg\n" ] } ], "source": [ "query_block = tmol.block_for_residue_label(pose_stack, 0, \"A\", 43)\n", "block_type = pose_stack.block_type(0, query_block)\n", "print(f\"chain A residue 43 -> block {query_block} ({block_type.name3})\")\n", "print(\"available torsions:\", tmol.get_torsion_names(pose_stack, 0, query_block))\n", "\n", "phi = tmol.get_named_torsions(pose_stack, 0, query_block, \"phi\")\n", "psi = tmol.get_named_torsions(pose_stack, 0, query_block, \"psi\")\n", "print(f\"phi={phi:.1f} deg, psi={psi:.1f} deg\")\n" ] }, { "cell_type": "markdown", "id": "4806cbc1", "metadata": {}, "source": [ "#### Stacked pose querying" ] }, { "cell_type": "code", "execution_count": 10, "id": "97bcc8ee", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:16.108068Z", "iopub.status.busy": "2026-10-20T00:48:16.107803Z", "iopub.status.idle": "2026-10-20T00:48:16.114863Z", "shell.execute_reply": "2026-10-20T00:48:16.114057Z" } }, "outputs": [ { "data": { "text/plain": [ "'MQIFVKTLTGKTITLEVEPSDTIENVKAKIQDKEGIPPDQQRLIFAGKQLEDGRTLSDYNIQKESTLHLVLRLRGG'" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Some functions can work on the whole pose stack\n", "tmol.get_sequence(multi_pdb_stack)" ] }, { "cell_type": "code", "execution_count": 11, "id": "31afb708", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:16.116848Z", "iopub.status.busy": "2026-10-20T00:48:16.116530Z", "iopub.status.idle": "2026-10-20T00:48:16.122414Z", "shell.execute_reply": "2026-10-20T00:48:16.121556Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "pose 0: 76 blocks, starts MQIFVKTLTGKTITLEVEPS...\n", "pose 1: 225 blocks, starts IVGGYTCGANTVPYQVSLNS...\n" ] } ], "source": [ "# Others you must extract the individual poses\n", "for pose_index in range(multi_pdb_stack.n_poses):\n", " single = multi_pdb_stack.split(pose_index)\n", " single_sequence = tmol.get_sequence(single)\n", " print(f\"pose {pose_index}: {len(single_sequence)} blocks, starts {single_sequence[:20]}...\")\n" ] }, { "cell_type": "markdown", "id": "2439fa27", "metadata": {}, "source": [ "### Setting basic info in the PoseStack" ] }, { "cell_type": "markdown", "id": "20955232", "metadata": {}, "source": [ "#### Set a residue's sidechain chi angles" ] }, { "cell_type": "markdown", "id": "7f9d0162", "metadata": {}, "source": [ "Torsion values can be set directly by name using `tmol.set_named_torsions`. This returns a new `PoseStack` with the updated coordinates from the moves." ] }, { "cell_type": "code", "execution_count": 12, "id": "7af25ccb", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:16.124867Z", "iopub.status.busy": "2026-10-20T00:48:16.124577Z", "iopub.status.idle": "2026-10-20T00:48:20.455974Z", "shell.execute_reply": "2026-10-20T00:48:20.454952Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "block 42 (LEU) chi1: -68.3 -> -38.3 deg\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n", "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n", "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n", "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n" ] }, { "data": { "text/html": [ "\n", "
\n", " \n", "
\n", " \n", "
\n", "
chi1=-68.3 deg
\n", "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "\n", "
\n", "
\n", "
chi1=-38.3 deg
\n", "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "\n", "
\n", "
\n", "
original vs. chi1 rotated
\n", "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "\n", "
\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# block 42 (LEU, found above as chain A residue 43) has a chi1 torsion\n", "before_chi1 = tmol.get_named_torsions(pose_stack, 0, query_block, \"chi1\")\n", "rotated_pose_stack = tmol.set_named_torsions(\n", " pose_stack, 0, query_block, \"chi1\", before_chi1 + 30.0\n", ")\n", "after_chi1 = tmol.get_named_torsions(rotated_pose_stack, 0, query_block, \"chi1\")\n", "print(\n", " f\"block {query_block} ({pose_stack.block_type(0, query_block).name3}) chi1: \"\n", " f\"{before_chi1:.1f} -> {after_chi1:.1f} deg\"\n", ")\n", "\n", "display(tmol.overlay_view(\n", " {\"original\": pose_stack, \"chi1 rotated\": rotated_pose_stack},\n", " notes={\"original\": f\"chi1={before_chi1:.1f} deg\", \"chi1 rotated\": f\"chi1={after_chi1:.1f} deg\"},\n", "))\n" ] }, { "cell_type": "markdown", "id": "26d449cf", "metadata": {}, "source": [ "#### Modify a residue's identity" ] }, { "cell_type": "markdown", "id": "c8ecf23e", "metadata": {}, "source": [ "`tmol.mutate_residue` wraps the packer-based mutation above into a single call: it restricts packing to one block, narrows its allowed identity to the requested one, and runs `pack_rotamers` with a Dunbrack sampler for the new identity. The input `PoseStack` is left unchanged." ] }, { "cell_type": "code", "execution_count": 13, "id": "4651f501", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:20.460089Z", "iopub.status.busy": "2026-10-20T00:48:20.459879Z", "iopub.status.idle": "2026-10-20T00:48:24.055225Z", "shell.execute_reply": "2026-10-20T00:48:24.054370Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "block 42: LEU -> ALA\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n", "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n", "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n", "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n" ] }, { "data": { "text/html": [ "\n", "
\n", " \n", "
\n", " \n", "
\n", "
block 42: LEU
\n", "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "\n", "
\n", "
\n", "
block 42: ALA
\n", "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "\n", "
\n", "
\n", "
original vs. mutated
\n", "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "\n", "
\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "mutated_pose_stack = tmol.mutate_residue(\n", " pose_stack, 0, query_block, \"ALA\", param_db=param_db\n", ")\n", "print(\n", " f\"block {query_block}: \"\n", " f\"{pose_stack.block_type(0, query_block).name3} -> \"\n", " f\"{mutated_pose_stack.block_type(0, query_block).name3}\"\n", ")\n", "\n", "display(tmol.overlay_view(\n", " {\"original\": pose_stack, \"mutated\": mutated_pose_stack},\n", " notes={\n", " \"original\": f\"block {query_block}: {pose_stack.block_type(0, query_block).name3}\",\n", " \"mutated\": f\"block {query_block}: {mutated_pose_stack.block_type(0, query_block).name3}\",\n", " },\n", "))\n" ] }, { "cell_type": "markdown", "id": "9f944c30", "metadata": {}, "source": [ "#### Mutate to match a target sequence" ] }, { "cell_type": "markdown", "id": "8bcf71a9", "metadata": {}, "source": [ "`tmol.mutate_to_sequence` does the same for a whole one-letter sequence at once: every position whose identity already matches is left untouched, and every differing position is redesigned together in a single packing run." ] }, { "cell_type": "code", "execution_count": 14, "id": "3447cf6a", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:24.059995Z", "iopub.status.busy": "2026-10-20T00:48:24.059681Z", "iopub.status.idle": "2026-10-20T00:48:24.562111Z", "shell.execute_reply": "2026-10-20T00:48:24.561084Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "block 42: LEU -> GLY\n", "sequence now matches target: True\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n", "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n", "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n", "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n" ] }, { "data": { "text/html": [ "\n", "
\n", " \n", "
\n", " \n", "
\n", "
block 42: LEU
\n", "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "\n", "
\n", "
\n", "
block 42: GLY
\n", "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "\n", "
\n", "
\n", "
original vs. resequenced
\n", "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "\n", "
\n", "
\n", "
\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "target_sequence = list(tmol.get_sequence(pose_stack))\n", "target_sequence[query_block] = \"G\"\n", "target_sequence = \"\".join(target_sequence)\n", "\n", "resequenced_pose_stack = tmol.mutate_to_sequence(\n", " pose_stack, 0, target_sequence, param_db=param_db\n", ")\n", "print(f\"block {query_block}: {pose_stack.block_type(0, query_block).name3} -> \"\n", " f\"{resequenced_pose_stack.block_type(0, query_block).name3}\")\n", "print(\"sequence now matches target:\", tmol.get_sequence(resequenced_pose_stack) == target_sequence)\n", "\n", "display(tmol.overlay_view(\n", " {\"original\": pose_stack, \"resequenced\": resequenced_pose_stack},\n", " notes={\n", " \"original\": f\"block {query_block}: {pose_stack.block_type(0, query_block).name3}\",\n", " \"resequenced\": f\"block {query_block}: {resequenced_pose_stack.block_type(0, query_block).name3}\",\n", " },\n", "))\n" ] }, { "cell_type": "markdown", "id": "3fdca18b", "metadata": {}, "source": [ "### Writing outputs - TODO" ] }, { "cell_type": "markdown", "id": "1b162e56", "metadata": {}, "source": [ "TODO - this section is using the old pdb writer. There are functions for writing through biotite/atomworks, but these have the limitation of only being able to output structures with the same chemical identity. So they are not a general solution for a write-pdb/cif one liner. How do we want to resolve this?\n", "\n", "`file_from_pose_stack` saves a `PoseStack` to a PDB file. `tmol.view` renders a `PoseStack` (or a Biotite structure, or raw PDB text) in an interactive py3Dmol viewer." ] }, { "cell_type": "code", "execution_count": 15, "id": "899cf414", "metadata": { "execution": { "iopub.execute_input": "2026-10-20T00:48:24.566504Z", "iopub.status.busy": "2026-10-20T00:48:24.566226Z", "iopub.status.idle": "2026-10-20T00:48:24.755023Z", "shell.execute_reply": "2026-10-20T00:48:24.754051Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "wrote /tmp/1ubq_mutated.pdb\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n", "/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.\n", " record = np.char.array(np.where(array.hetero, \"HETATM\", \"ATOM\"))\n" ] }, { "data": { "application/3dmoljs_load.v0": "
\n

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n
\n", "text/html": [ "
\n", "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import tempfile\n", "from pathlib import Path\n", "\n", "output_path = Path(tempfile.gettempdir()) / f\"{PDB_ID.lower()}_mutated.pdb\"\n", "file_from_pose_stack(mutated_pose_stack, str(output_path))\n", "print(f\"wrote {output_path}\")\n", "\n", "viewer = tmol.view(mutated_pose_stack)\n", "viewer.show()\n" ] } ], "metadata": { "accelerator": "GPU", "colab": { "gpuType": "T4" }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.12" }, "tmol": { "gpu_smoke": true } }, "nbformat": 4, "nbformat_minor": 5 }