{ "cells": [ { "cell_type": "markdown", "id": "69ad33c3", "metadata": {}, "source": [ "# Case Study 09 — Map and Test a Protein Interface\n", "\n", "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/uw-ipd/tmol/blob/master/docs/tutorial/09_protein_interface_hotspot_scan.ipynb)\n", "\n", "Which side chains appear to stabilize a protein–protein interface, and what\n", "happens when they are replaced by alanine? This capstone follows one scientific\n", "question through structure inspection, score decomposition, a batched local\n", "repacking experiment, and interactive comparison of the resulting structures.\n", "\n", "## Learning objectives\n", "\n", "- Define an interface from author chain labels rather than block positions.\n", "- Rank residue contributions from both orientations of a block-pair score tensor.\n", "- Run matched WT/alanine local-repacking tasks in one `PoseStack` batch.\n", "- Separate one-complex score changes from thermodynamic binding ΔΔG.\n", "\n", "## Before you begin\n", "\n", "- **Prerequisites:** [03 — Scoring](03_scoring_and_analysis.ipynb) and [04 — Packing](04_packing_and_mutation_scan.ipynb).\n", "- **Related:** [Protein-interface workflow](../workflows/protein_interfaces.md) · [Packing API](../api/pack.rst) · [Scoring API](../api/score.rst)\n", "\n", "The example extracts neighboring chains A and B from the checked-in KcsA\n", "tetramer structure (PDB 1BL8). It therefore analyzes one subunit interface, not\n", "the complete tetramer or a membrane-aware binding process. The workflow uses\n", "weighted TMol score units; it does not estimate kcal/mol or experimental\n", "affinity." ] }, { "cell_type": "markdown", "id": "4fc7e4f8", "metadata": {}, "source": [ "## Setup\n", "\n", "The setup fixes PyTorch's random seed, loads protein atoms from chains A and B,\n", "and optimizes hydrogen coordinates before interpreting all-atom scores. TMol's\n", "CPU packer uses a C random stream that `torch.manual_seed()` does not control;\n", "the CPU results below are illustrative single outcomes rather than replicates." ] }, { "cell_type": "code", "execution_count": 1, "id": "b1fbcf38", "metadata": {}, "outputs": [], "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 urlopen\n", "\n", " exec(\n", " urlopen(\n", " \"https://raw.githubusercontent.com/uw-ipd/tmol/\"\n", " \"master/docs/tutorial/colab_setup.py\"\n", " ).read(),\n", " globals(),\n", " )\n", " setup_colab([\"tmol/tests/data/cif/1BL8.cif\"])" ] }, { "cell_type": "code", "execution_count": 2, "id": "c75da2e4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "device=cpu; input=1BL8.cif; blocks=194; chains=A+B\n" ] } ], "source": [ "from contextlib import redirect_stderr, redirect_stdout\n", "from io import StringIO\n", "from pathlib import Path\n", "from time import perf_counter\n", "import warnings\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "import torch\n", "from IPython.display import display\n", "from biotite.structure.io import load_structure\n", "\n", "import tmol\n", "from tmol.database import ParameterDatabase\n", "from tmol.io import pose_stack_from_biotite\n", "from tmol.ops import (\n", " calculate_block_pair_ddg,\n", " compute_block_adjacency,\n", " compute_block_centroids_and_furthest_dist,\n", " res_mask_to_coord_mask,\n", ")\n", "from tmol.pack import PackerPalette, PackerTask, pack_rotamers\n", "from tmol.pack.rotamer import FixedAAChiSampler, IncludeCurrentSampler\n", "from tmol.pack.rotamer.dunbrack import create_dunbrack_sampler_from_database\n", "from tmol.pose import PoseStackBuilder\n", "from tmol.score import ScoreType, beta2016_score_function\n", "\n", "SEED = 20260829\n", "np.random.seed(SEED)\n", "torch.manual_seed(SEED)\n", "if torch.cuda.is_available():\n", " torch.cuda.manual_seed_all(SEED)\n", "warnings.filterwarnings(\n", " \"ignore\", message=r\"Sparse invariant checks are implicitly disabled.*\"\n", ")\n", "\n", "device = (\n", " torch.device(\"cuda\", torch.cuda.current_device())\n", " if torch.cuda.is_available()\n", " else torch.device(\"cpu\")\n", ")\n", "repo_root = Path.cwd()\n", "if not (repo_root / \"tmol/tests/data/cif/1BL8.cif\").exists():\n", " repo_root = Path(tmol.__file__).resolve().parents[1]\n", "cif_path = repo_root / \"tmol/tests/data/cif/1BL8.cif\"\n", "\n", "atom_array = load_structure(str(cif_path), model=1, include_bonds=True)\n", "protein_dimer = atom_array[\n", " ((atom_array.chain_id == \"A\") | (atom_array.chain_id == \"B\")) & ~atom_array.hetero\n", "]\n", "param_db = ParameterDatabase.get_default()\n", "pose_diagnostics = StringIO()\n", "try:\n", " with redirect_stdout(pose_diagnostics), redirect_stderr(pose_diagnostics):\n", " pose_stack = pose_stack_from_biotite(\n", " protein_dimer,\n", " device,\n", " param_db=param_db,\n", " no_optH=False,\n", " )\n", "except Exception:\n", " print(pose_diagnostics.getvalue())\n", " raise\n", "\n", "score_function = beta2016_score_function(device, param_db=param_db)\n", "\n", "\n", "def show_table(frame):\n", " try:\n", " from itables import show\n", " except ImportError:\n", " display(frame)\n", " return None\n", " return show(frame)\n", "\n", "\n", "def block_label(pose, block_index):\n", " chain = pose.pdb_info.chain_labels[0, block_index]\n", " residue = pose.pdb_info.residue_labels[0, block_index]\n", " insertion = pose.pdb_info.residue_insertion_codes[0, block_index]\n", " return f\"{chain}:{residue}{insertion}\"\n", "\n", "\n", "chain_labels = pose_stack.pdb_info.chain_labels[0]\n", "chain_a = torch.tensor([str(label) == \"A\" for label in chain_labels], device=device)\n", "chain_b = torch.tensor([str(label) == \"B\" for label in chain_labels], device=device)\n", "assert int(chain_a.sum()) == int(chain_b.sum()) == 97\n", "print(\n", " f\"device={device}; input={cif_path.name}; \"\n", " f\"blocks={pose_stack.max_n_blocks}; chains=A+B\"\n", ")" ] }, { "cell_type": "markdown", "id": "dd17c467", "metadata": {}, "source": [ "## Inspect the extracted neighboring-subunit interface\n", "\n", "The author chain labels survive pose construction and define the two partners.\n", "The viewer highlights chain A in blue within the extracted A–B dimer. This is a\n", "specific neighboring interface from the crystallographic tetramer; chains C and\n", "D, membrane context, ions, solvent, and separated partners are outside this\n", "case study." ] }, { "cell_type": "code", "execution_count": 3, "id": "a1a0a230", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Blue: chain A; unhighlighted partner: chain B.\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": [ "chain_a_atoms = res_mask_to_coord_mask(pose_stack, chain_a.unsqueeze(0))\n", "try:\n", " interface_viewer = tmol.view(\n", " pose_stack,\n", " highlighted=chain_a_atoms[pose_stack.real_atoms],\n", " highlight_color=\"#2563eb\",\n", " )\n", " print(\"Blue: chain A; unhighlighted partner: chain B.\")\n", " interface_viewer.show()\n", "except ImportError as exc:\n", " print(\"Interactive interface viewer unavailable:\", exc)" ] }, { "cell_type": "markdown", "id": "6ac7f0f6", "metadata": {}, "source": [ "## Map native interface contributions\n", "\n", "The block-pair scorer stores each unordered interaction in one directed matrix\n", "entry. For every A–B pair, the analysis therefore adds `A→B` and `B→A` before\n", "ranking residues. The hotspot ranking uses five explicit nonbonded terms:\n", "`fa_ljatr`, `fa_ljrep`, `fa_lk`, `fa_elec`, and `hbond`. The complete all-term\n", "cross-chain reduction is independently checked with\n", "`calculate_block_pair_ddg()` despite that helper's historical name.\n", "\n", "The heat map is an energetic accounting view of this one fixed complex, not a\n", "contact probability or experimental residue contribution. Negative values are\n", "more favorable under the chosen weighted-term subset." ] }, { "cell_type": "code", "execution_count": 4, "id": "843a778b", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", " \n", " \n", " \n", " \n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
block_indexauthor_labelidentityfive_term_interface_score
5555A:78TYR-6.986693
182182B:108ALA-4.855327
8080A:103PHE-4.636461
9898B:24LEU-4.392589
156156B:82TYR-3.430952
8888A:111ALA-3.005775
9292A:115VAL-2.759967
9090A:113TRP-2.212948
146146B:72THR-1.648886
4444A:67TRP-1.638673
(6 more rows not shown)
\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAzgAAAKACAYAAABQYt0uAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAh0RJREFUeJzs3Xd0VNX6//HPpAdS6D30Jk1ApEiAAAqoNClKUSmiIl7rRSkqWC4XuaKiKDZEBRVRQaqKUqSINCnSOxhaKCEktIRk9u8PfsyXMTMwM5lMksn7tdZZK9lnn2fvOZPAPHnO2cdijDECAAAAAD8QkNMTAAAAAABvIcEBAAAA4DdIcAAAAAD4DRIcAAAAAH6DBAcAAACA3yDBAQAAAOA3SHAAAAAA+A0SHAAAAAB+gwQHAAAAgN8gwQGQZ5QrV073339/Tk8jkw4dOqh+/fo5EtOdc1KnTh117do1axPz0lx8Jbtfc37D+QSQF5DgwK/FxsaqVKlSmdq3bNmiMmXKqGzZstqyZUu2jd+sWTNZLBa98MILORpDunIuLBaLbQsKClL58uV177336q+//spSbAD+o2rVqurRo0dOTwMAPEaCg3xn5cqVatmypSIjI/X777+rbt262TLOtm3btHr1apUrV06fffaZ0tPTcyTGtUqWLCljjIwxunjxoubNm6dDhw6pWbNm2r9/f5ZiA7nR1q1bNXv27Jyeht/gfALIC0hwkK/MnTtX7dq1U9WqVbVy5UpVrFgx28b65JNPVLRoUU2fPl3Hjh3TggULciSGM8HBwbr55pv13//+VxcuXOBDCwAA8AskOMg3PvvsM3Xr1k3NmzfX0qVLVbx48Ux9Zs6cqZYtWyoqKkqFCxfWnXfeqXXr1tn2//zzz2rZsqWKFCmiwoULKzY2VrNmzcoUJzU1VdOmTdPAgQMVGxurRo0aafLkyW7N1xsx3BEWFnbDPlfvsdiyZYtatWql8PBwlS9fXuPHj8/U1xijCRMmqHbt2goLC1PRokXVrVs37dixw+OYV61du1bNmjVTeHi4KlasqP/9738yxmT7+Onp6XrxxRdVrlw5FShQQK1bt9b27dudzvP7779X8+bNFRERoQIFCqhVq1ZatmxZlmJm5Zw44up5km78++HIRx99pODgYD3zzDOyWq3X7Xv1vXDltdx+++22yy0DAwNVqlQp9erVSwcOHLDr5+iekavjbNiwQa1atVKBAgU0dOhQp/NydSxXz9GN+rj6nlgsFg0fPtzhfBs1auTwNd/o5zwoKEj79u3TzJkzba+5Tp06Lp1PV36HLl++rJEjR6ps2bJ2P+/ZcR8bgHzMAH6sefPmpmTJkmbcuHFGkrnvvvtMamqqw77/+c9/TEBAgBk5cqTZv3+/SUpKMgsXLjR9+vQxxhizZcsWExwcbIYPH24SEhLMuXPnzB9//GF69Ohhjh8/bhfr66+/NhaLxezbt88YY8yUKVNMYGCgOXz4sMtz90aMa109F1elpaWZv/76yzRt2tSULFnSJCQk3DBG2bJlTdu2bU23bt3Mli1bzJkzZ8xrr71mJJl58+bZ9X3sscdMSEiImTRpkjl9+rTZtm2badGihYmKijI7duzwKGbZsmVN69atzV133WW2bt1qEhMTzXvvvWeCgoLMyJEjs338gQMHmvDwcPPFF1+YpKQks379etOuXTvTpEkTc/PNN9v1ff31101AQIAZM2aMOXLkiElISDAjR440QUFBZsmSJR7FdPaeuHpOateubbp06eLRebrR78fVufTt29cYY0xGRoZ59tlnTVBQkPnggw9u+DrcfS3XunTpklm/fr2JjY01NWvWNBcuXLjua752nL/++sscPXrUzJw506U5Xm8sV86RK31cfU8kmWHDhmWaY9u2bc0tt9yS6TW7+nNepUoV0717d4ev39n5dDV2v379TIECBcyXX35pkpKSzMaNG81dd93l8s87ALiCBAd+rXnz5kaSkWRatWplMjIyHPY7ePCgCQoKMo888ojTWB9++KGR5FIi0Lp1a3PnnXfavr9w4YIpUqSIefXVV12euzdiXOvac3HtVq5cOfP777+7FKNs2bKmYMGC5sSJE7Y2q9VqKleubDp16mRr27lzp7FYLObZZ5+1O/7UqVOmYMGCdh+eXI15tW9oaKg5duyYXfvgwYNNcHCw7b3JjvF37txpJJnRo0fbxdy+fbuxWCx2H87i4+NNcHCwefzxx80/xcXFmSZNmrgd0xlXz4kxmT+cunqeXPn9uDqXvn37mnPnzpnOnTubqKgos3Dhwhu+Bk9eiyNbt241kszPP/9sa3P2gTwkJMQcPXrU5bndaCxXzpErfdz52XU3wXH198yTBMeV2Dt27DCSzCuvvGJ3/O7du01AQAAJDgCv4RI1+L3ChQurZcuWWr58uT788EOHfX755Relp6erT58+TuPUq1dPktSvXz8tWrRIFy9edNhv3759+u233zRkyBBbW3h4uPr3768pU6bc8DIdb8Vw5NpFBjIyMrR//37dfvvtuv3227VkyRKXYjRu3Nju8j6LxaLatWvbLVKwdOlSGWPUrVs3u2OLFi2quLg4LV682O2Y1/b958p4Xbt21eXLl7VixYpsG//q+encubPdsTfddJNq1Khh17Zw4UJdvnxZPXv2zDT/22+/XevWrdPFixfdink9rpwTR1w9T678flx17NgxxcbG6q+//tKqVavUrl07u/2DBg2yW82vatWqHr2WPXv2qG/fvipbtqyCg4PtLqXau3fvDed56623qnTp0jfs5+pYrpwjV/q4+7PrDnd+z7Ij9tKlSyVJnTp1sju2WrVqqlmzZpbnAABXkeDA74WEhOinn35SmzZt9Pjjj+vtt9/O1OfEiROSpLJlyzqN06xZM02fPl0nTpxQu3btFB0drbi4OH3//fd2/SZPnixjjDp16mT3Qe6tt97SwYMHtWjRohvO2Z0Y//zAeO22cuVKp2MEBASoUqVK+vjjjxUZGXndexCu5ehDYVRUlJKSkmzfnz59WpIcLtFdqlQpJSUlKSMjw62YV5UsWdJp26lTp7Jt/Ksxrzf+VcePH5cktW3bVkFBQQoMDFRAQIACAgL04osvymq16syZM27FvB5Xzokjrp4nV34/rvrrr7+0adMm3X333apdu7ZL83c0b0dtV1/LmTNn1Lx5cx04cECzZ89WUlKSjDE6ePCgpCv3edyIK6/FnbFcOUeu9HH3Z9cR4+TeK3d+z9zlzu9QiRIlMvV11AYAniLBQb5QoEABzZ8/X3feeaeeffZZjRs3zm7/1b88Hjly5LpxevXqpT///FOnTp3S999/r9DQUPXs2dO2All6ero+//xzjR8/3lYpuXbr0qWLPvnkk+uO4W6Mq8mQoy02NvaG5yY4OFgVK1bU1q1bb9hXuvKX2RspUqSIJCkhISHTvoSEBBUqVEiBgYFuxbz2eGdtRYsWzbbxr8a+3vhXFStWTJK0Zs0apaenKyMjQ1arVVar1fbelClTxq2Y1+PKOXHE1fPk6u+HJLVv316TJk3SBx98oMGDB2eqNv7z5/Wf1RZXXstPP/2kkydPasKECbr11ltVsGBBSXJ4078zwcHBLvVzdSxXzpErfdz52Y2KilJKSkqmfs7iu/N75i53foeuJnrXctQGAJ4iwUG+ERYWptmzZ6tz584aPny4Xn31Vdu+9u3bKygoSF9//bVLsYoUKaLOnTtr5syZkqTly5dLkubNm6fjx4+rQ4cODo+78847NWfOHJ08edJpbG/EcMfly5d14MABh38x9lSbNm0kST/88INde2Jion777Te1bdvW49jr1q3L9OFvzpw5Cg4OVosWLbJt/NatW0u68v5ca+fOndq9e7ddW4cOHRQUFKQZM2Z4Leb1uHJOHHH1PLn7+/HYY4/pyy+/1JQpU9S3b1+XKiqevJbQ0FC776dOneryOO660ViunCNX+rjzs1ulSpVMf5jYtWuXS5foXU/BggWVmpqapRiOXP15/+dy93v37tXOnTu9Ph6A/IsEB/lKSEiIvv/+e/Xs2VOjR4/Wiy++KEmqUKGCRo8ercmTJ+uFF17QwYMHlZycrF9++UV9+/aVJI0fP17PP/+8NmzYoHPnzikxMVHvvvuuJCkuLk7Slb9OlytXzumlOXfeeacuX76sL774wukcvRHDFVarVQcPHtQjjzyikydP6rnnnstSvGvVqFFDjzzyiN599119/PHHOnPmjHbs2KHu3btLkl1y6a6mTZtq0KBB2r59u86cOaMPPvhAkydP1rPPPmu7lCk7xq9Zs6b69++vN954Q1999ZWSk5O1ceNGPfPMM7r11lvt+laoUEFjxozRW2+9pZdfflkHDhzQxYsXtXPnTr333nvq16+f2zGzek4ccfU8ufL78U+9e/fW7NmzNWfOHHXp0sXpPWuevJa4uDhFRkZqxIgROnz4sE6cOKH//ve/On/+vMvnzFWujuXKOXKljzs/uw8//LCWL1+uTz/9VCkpKVq3bp2GDRumW265JUuvuU6dOtq4caP+/vvvLMX5p5o1a6pfv34aN26cpk+fruTkZG3evNntn3cAuKHsX8cAyDn/XBr5qvT0dNO3b18jyQwdOtTWPmPGDHPbbbeZAgUKmCJFipg777zTrF271hhjTFJSkhk/frxp1KiRKViwoClatKhp1aqV+eGHH4wxV1bOCggIMIMGDbrunGrVqmVq1KjhcJ83Yjjzz1XULBaLKVWqlGnTpk2mpVyduXYZ4Gv17dvXlC1b1q4tIyPDjB8/3tx0000mJCTEFCpUyHTp0sVs2bLF45hX+/7xxx+mcePGJjQ01JQvX96MHTvWWK3WbB8/LS3NjBgxwpQuXdqEhYWZFi1amC1btpj27ds7XAFq/vz55vbbbzeFChUyYWFhplatWuapp54y+/fv9zjmP7lzThytgOXqeTLm+r8fzs7l8uXLTXR0tGnRooVJSkry2mtZtmyZadKkiSlQoIApU6aMGT58uImPjzeSzNtvv33d1+zsPXfG1bFcOUeu9HH1PUlPTzfDhw83JUqUMOHh4aZdu3Zm//79TldRc/XnfP/+/SYuLs4ULFjQSDK1a9e27XPnfDr7HRo+fLjt571Vq1Zm69atJi4uzjRu3DhTDADwhMUYF54EBwBANitXrpzi4uL05Zdf5vRU4GPVqlVTrVq1NGfOnJyeCgA/wCVqAAAgx2zevFn79u1Tq1atcnoqAPxEUE5PAAAA5A8zZ87U/v371b17d5UoUULr1q3TY489ppiYGD300EM5PT0AfoIKDgAA8In27dsrMTFRd911l4oVK6ZevXrp1ltv1cqVKxUdHZ3T0wPynLS0NP3www+aMmWKy8ckJSVp1qxZ+uabb3T06FGP++Rm3IMDAAAA5DFjx47V+++/r+joaO3atUvp6ek3PGbVqlXq2LGjatasqcjISK1cuVKffvqpevXq5Vaf3I4KDgAAAJDHlC1bVhs2bHD5MQ9Wq1UPPvigunXrplWrVmnhwoV66aWX9MgjjygxMdHlPnlBnkhwTp8+rQ8++EAvv/yyZs6cmenJ2AAAAEB+8uCDD6pEiRIu91+3bp327dunJ554wtb22GOP6dKlS5o/f77LffKCXL/IwIEDB9S8eXNVr15dt956q/79739rypQpmjdvngICXMvPrFarjh49qsjISFkslmyeMQAAAFxljFFKSorKlCnj8mc7X7l06ZLS0tJ8Np4xJtNn1dDQUIWGhmY59tatWyVJtWrVsrVFR0erbNmytn2u9MkLcn2CM2zYMFWsWFGLFy9WYGCgHnvsMdWoUUMzZsxQ7969XYpx9OhRxcTEZPNMAQAA4Kn4+HiVK1cup6dhc+nSJZUJj9AZZfhszIiICJ07d86ubfTo0Xr55ZezHDs5OVkFCxZUcHCwXXuRIkWUnJzscp+8IFcnOOnp6Zo3b57efPNNBQYGSpIqV66sVq1aadasWS4nOJGRkZKklSuWKyIiItvmCwAAAPecO3dOsS1a2j6v5RZpaWk6owx9HlhJBXxwV8cFWdX/3AHFx8crKirK1u6N6o0khYeH68KFC8rIyLB9rpaklJQUhYeHu9wnL8jVCc7ff/+tS5cuqWrVqnbtVatW1R9//OH0uNTUVKWmptq+T0lJkXQlK85tvzwAAABQrr2NoIACVMASeOOOWfX/1zWOioqyS3C8pWrVqjLG6O+//1alSpUkXUnijh49avus7UqfvCB3Xej4D+fPn5ekTG9ydHS0bZ8jY8eOVXR0tG3j8jQAAAB4whJs8dnmbTNmzNDq1aslSbGxsSpUqJCmT59u2z9nzhxdunRJd911l8t98oJcXcG5ejnZ2bNn7dqTkpKue6nZiBEj9Oyzz9q+T05OJskBAACA3/jtt9+0d+9erVq1SsYYTZ48WZLUqVMnlSxZUtKVe9m7du2qpk2bKiwsTG+//bYeeeQRnT59WhEREXrnnXf0/PPP26o1rvTJC3J1glO+fHkVLFhQu3btUvv27W3tu3bt0k033eT0OG+tNgEAAID8zRJkUYAPLp+zGPfG2Ldvn1avXq2AgAANGDDAVqmJi4uzJTi9evVSgwYNbMf0799fNWrU0KxZs5SUlKSvvvpKd999t11cV/rkdhZjjMnpSVzPAw88oB07dmjVqlUKCQnR9u3bVa9ePX377bfq1q2bSzGSk5MVHR2tTRs3cA8OAABALpKSkqL6DRrq7Nmz2XLviaeufn78PqKaCvrgHpzzJkM9zu3JdechL8rVFRxJev3119WiRQs1a9ZMt9xyi+bOnasePXronnvuyempAQAAwM9ZggNksWT/beuW3F1zyFNyfYJTtmxZ/fXXX5o7d64SEhJ077336vbbb8/paQEAAADIhXJ9giNdWWygT58+OT0NAAAA5DMBgRYFBGT/PTgB1ty5THZelKuXiQYAAAAAd+SJCg4AAACQEyzBFll8UMGxUMHxGio4AAAAAPwGFRwAAADAiYAg7sHJa6jgAAAAAPAbJDgAAAAA/AaXqAEAAABOsMhA3kMFBwAAAIDfoIIDAAAAOBEQaFFAoA8WGcigguMtVHAAAAAA+A0qOAAAAIATlkCLLD6o4FhEBcdbqOAAAAAA8BtUcAAAAAAnfHYPDhUcr6GCAwAAAMBvUMEBAAAAnLAE+Og5OIYKjrdQwQEAAADgN6jgAAAAAE5YAgNkCcz+moBFJtvHyC+o4AAAAADwGyQ4AAAAAPwGl6gBAAAATrBMdN5DBQcAAACA36CCAwAAADhhsfhomWgrFRxvoYIDAAAAwG9QwQEAAACcsATKJ/fgWFgl2muo4AAAAADwG1RwAAAAACcsgRZZfFLB4R4cb6GCAwAAAMBvUMEBAAAAnLAEBMgSkP01AV+MkV9wJgEAAAD4DSo4AAAAgBOWAB89B8cHY+QXVHAAAAAA+A0SHAAAAAB+g0vUAAAAACcCAi0+edBnAMtEew0VHAAAAAB+gwoOAAAA4ASLDOQ9VHAAAAAA+A0qOAAAAIATFouPHvRpoe7gLZxJAAAAAH6DCg4AAADgBPfg5D1UcAAAAAD4DSo4AAAAgBM+ew6OlQqOt1DBAQAAAOA3qOAAAAAATnAPTt5DBQcAAACA3yDBAQAAAOA3uEQNAAAAcMIS4KMHffpgjPyCMwkAAADAb1DBAQAAAJxgkYG8hwoOAAAAAL9BBQcAAABwggpO3kMFBwAAAIDfoIIDAAAAOEEFJ++hggMAAADAb1DBAQAAAJy4UsHxxXNwqOB4CxUcAAAAAH6DBAcAAABwwhJgUUBg9m/uVnDOnTunhx9+WEWKFFFERIS6deumo0ePOu2/evVqWSwWh9vcuXNt/apWrZpp/9NPP+3p6csRJDgAAABAHvPwww9rxYoVWrlypXbs2KGkpCR16tRJVqvVYf+mTZvKGGO3jRgxQtHR0br99tvt+n7wwQd2/SZMmOCDV+Q93IMDAAAA5CHx8fGaMWOGZs+erVq1akmS3nvvPdWuXVtLly5V27ZtbxgjIyNDX3zxhfr27asCBQpk95R9igoOAAAA4MTVZaJ9sbnqjz/+kDFGcXFxtrZatWqpZMmSWrVqlUsxfvrpJx09elQPP/xwpn0jRoxQaGioqlatqmHDhun8+fMuzy03IMEBAAAAconk5GS7LTU1NVOf48ePKyQkRFFRUXbtJUqU0PHjx10a59NPP1WjRo1Uv359u/YOHTrol19+0enTp/Xxxx/r22+/1QMPPODx68kJJDgAAACAE5aAAJ9tkhQTE6Po6GjbNnbsWMfzsmSu+BhjHLb/U0JCgubPn++wevPee+/p1ltvVUREhNq0aaOJEyfqhx9+0P79+908czmHe3AAAACAXCI+Pt6uMhMaGpqpT6lSpZSamqrk5GS7vidPnlTJkiVvOMbUqVMVGhqq3r1737Bv3bp1JUl79uxR5cqVXXkJOY4KDgAAAOCEr+/BiYqKstscJTjNmjWTxWLR0qVLbW07duxQQkKCbrvtthu+pilTpqhXr16KjIy8Yd8tW7ZIksqUKePqKctxJDgAAABAHhITE6N7771Xw4cP144dOxQfH68hQ4aoYcOGat26ta1fxYoVMz3D5vfff9fOnTsdXp7266+/auTIkdq1a5cuXLigpUuX6oknnlDbtm1tlZy8gAQHAAAAcCI3rqImSZMnT1bz5s112223qWbNmipUqJDmzZungIDrf7z/9NNPVbduXTVp0iTTvlatWqlEiRLq3r27ihcvrsGDB6tv376aPXu2W3PLaRZjjMnpSWS35ORkRUdHa9PGDS6V4gAAAOAbKSkpqt+goc6ePZtpVbCcdPXz45Z+dykyJDjbx0tJu6y6X/yY685DXsQiAwAAAIAT165wlt3jwDs4kwAAAAD8BhUcAAAAwAlP7o/xdBx4BxUcAAAAAH6DBAcAAACA3+ASNQAAAMAJFhnIeziTAAAAAPwGFRwAAADAGYvlyuaLceAVVHAAAAAA+A0qOAAAAIATFouPlommguM1VHAAAAAA+A0qOAAAAIATrKKW93AmAQAAAPgNKjgAAACAE5YAH92D44Mx8gsqOAAAAAD8BhUcAAAAwAnuwcl7OJMAAAAA/AYJDgAAAAC/wSVqAAAAgBOWAN8sAGCh7OA1nEoAAAAAfoMKDgAAAOAEy0TnPVRwAAAAAPgNKjgAAACAMwEBVzZfjAOv4EwCAAAA8BtUcAAAAAAnLBaLLBYf3IPjgzHyCyo4AAAAAPwGFRwAAADACUtAgCw+uD/GF2PkF5xJAAAAAH6DCg4AAADgBM/ByXuo4AAAAADwGyQ4AAAAAPwGl6gBAAAAzlh89KBPC3UHb+FMAgAAAPAbVHAAAAAAZ3y0yIBYZMBrqOAAAAAA8BtUcAAAAAAnLJYAWXxwf4wvxsgvcsWZTE9PlzHmhv0uXbrkg9kAAAAAyKtyNMGZM2eOWrRooUKFCqlgwYJq27at/vrrr0z9Ro8erUKFCikiIkLVqlXTzz//nAOzBQAAQL4TYPHdBq/IsQQnIyNDn332mV5//XWdPn1ax48fV+nSpdW+fXudPXvW1m/ixImaMGGC5s+frwsXLmjAgAHq2rWr9u7dm1NTBwAAAJBL5ViCExgYqNmzZ6t58+YKDQ1VVFSUxo0bp+PHj2vNmjW2fhMmTNCgQYMUGxurkJAQjRw5UqVKldKHH36YU1MHAABAPmEJCPDZBu/IVWfy77//liQVK1ZMknTq1Cnt379fLVq0sOvXsmVLuyQIAAAAAKRctIpaamqqnnrqKd12221q0KCBJOnEiROS/i/huapEiRLXTXBSU1OVmppq+z45OTkbZgwAAAB/Z/HRc3B88qydfCJXVHDS09PVp08fJSQkaMaMGbJY7N9gq9Waqf8/+1xr7Nixio6Otm0xMTHZMm8AAAAAuUuOJzgZGRm6//77tW7dOv32228qV66cbV+ZMmUkSQkJCXbHnDhxwrbPkREjRujs2bO2LT4+PnsmDwAAACBXydEE52pys2rVKv3222+qVKmS3f5ChQqpTp06Wrx4sa3NarVqyZIlio2NdRr36qIF124AAACA2ywWyRLgg41L1Lwlx+7BsVqt6tevn5YsWaKffvpJRYoUUVJSkiSpQIECCgkJkSSNHDlS/fv3V4sWLdSsWTO98cYbSk1N1WOPPZZTUwcAAACQS+VYgpOUlKT58+dLktq0aWO3b+LEiXrggQckSb1799bFixc1btw4JSQkqG7dulqyZIlKly7t8zkDAAAgf2GRgbwnxxKcays2NzJw4EANHDgweycEAAAAIM/LNctEAwAAALlOQMCVzRfjwCs4kwAAAAD8BhUcAAAAwAmLxXLd5y96cxx4BxUcAAAAAH6DCg4AAADgjMVH9+BYqDt4C2cSAAAAgN+gggMAAAA4wXNw8h4qOAAAAAD8BgkOAAAAAL/BJWoAAACAM5YA3ywAwCIDXkOCAwAAAORB69at0w8//KC0tDS1a9dO7dq1u27/UaNG6cSJE3Ztbdu2Vc+ePbMUN7chVQQAAACcCbD4bnPDtGnT1Lx5c507d06hoaHq0aOHRo0add1jvv76a6WkpKh+/fq2rWzZslmOm9tQwQEAAADykNTUVD399NMaNWqUXnzxRUlS3bp1df/992vgwIGqWLGi02NbtGihwYMHez1ubkIFBwAAAHDCYgnw2eaqlStXKjExUX369LG13XPPPQoNDdWPP/543WN/+uknPfXUUxo/frx27drltbi5CQkOAAAAkEskJyfbbampqZn67NmzRxaLRRUqVLC1hYaGqkyZMtq7d6/T2OHh4SpWrJhiYmK0du1a3XzzzZo6dWqW4+Y2XKIGAAAAOOPB/TEejyMpJibGrnn06NF6+eWX7douXryoAgUKKDAw0K49KipKFy5ccDrEzz//bHfPzSuvvKLHH39cXbp0UXR0tMdxcxsqOAAAAEAuER8fr7Nnz9q2ESNGZOoTFRWl8+fP6/Lly3btZ86cUVRUlNPY/1xQoE+fPjp37pz++uuvLMXNbUhwAAAAACcsAQE+26QrSca1W2hoaKY51a5dW5K0Y8cOW1tycrKOHDli2+eKS5cuSZIyMjK8GjenkeAAAAAAeUjjxo1VqVIlvf/++7a2jz76SMHBwerYsaOt7YUXXtB3330nSdq9e7f27Nlj22e1WvXGG2+oSJEiuvXWW92Km9txDw4AAADgjMVyZfPFOC4KCAjQF198oU6dOmnnzp2KiIjQ0qVL9cknn6ho0aK2fl999ZXOnz+vnj17ymKx6L777lN0dLRiYmK0fv16paSk6Ntvv1XBggXdipvbkeAAAAAAeUyLFi20b98+LVq0SGlpafrggw9Uvnx5uz5jxoxRpUqVJEnVqlXTunXr9Mcff+jAgQMaMGCAmjZtqvDwcLfj5nYkOAAAAEAeVLRoUd13331O9/ft29fu+8DAQMXGxio2NjZLcXM7EhwAAADAmQCLFOCD29Z9sRR1PsEiAwAAAAD8BhUcAAAAwJlcuMgAro8KDgAAAAC/QQUHAAAAcOLah3Bm9zjwDs4kAAAAAL9BBQcAAABwxhJwZfPFOPAKziQAAAAAv0EFBwAAAHDGYvHNM2pYRc1rqOAAAAAA8BtUcAAAAAAnLJYAWXxwf4wvxsgvPDqT69ev9/Y8AAAAACDLPEpwmjRp4u15AAAAAECWeZTglC9fXvv27fP2XAAAAIDcJcDiuw1e4VGCM3r0aA0aNEhbt25Venq6t+cEAAAAAB7xaJGBQYMGKSMjQ3Xr1pXFYlFAgH2eRNIDAAAAv8CDPvMcjxKc+fPne3seAAAAAJBlHiU4HTp08PY8AAAAgNzHYvHNQzh50KfXeFwLs1qt2rx5s3744QdbW2pqqlcmBQAAAACe8CjBOXbsmJo1a6aGDRuqW7dutvZu3bpp4cKFXpscAAAAkKMCAny3wSs8OpPPPPOMqlevrrNnz9q1Dx8+XP/973+9MjEAAAAAcJdH9+AsXrxY27ZtU0REhF37zTffrLVr13plYgAAAECOYxW1PMejM3nhwgWFhIRIkizX3BB18uRJhYWFeWdmAAAAAOAmjxKc2NhYffbZZ5L+L8FJS0vTyJEjFRcX57XJAQAAADkqwOK7DV7h0SVqb7zxhuLi4rRw4UIZYzRgwAAtXbpUycnJWrVqlbfnCAAAAAAu8aiCU69ePW3evFk333yzWrdurYMHD6p79+7atGmTatas6e05AgAAAIBLPKrgSFJMTIzGjRvnzbkAAAAAuYvF4qNFBrhEzVs8TnAkKTExUYmJiZnaq1atmpWwAAAAAOARjxKcP//8U/fff7927tzpcL8xJkuTAgAAAHIFi8U31RUqOF7jUYIzePBgNWrUSF9//bUKFy7s7TkBAAAAgEc8SnC2b9+uRYsWKTo62tvzAQAAAHKPgIArmy/GgVd4dCYrVaqkM2fOeHsuAAAAAJAlHiU4w4YN0+DBg3XgwAFvzwcAAADIPa7eg+OLDV7h0SVqAwYMUEZGhipXrqyAgABZ/vGGpKene2VyAAAAAOAOjxKc+fPne3seAAAAQO5jCfDRc3C4B8dbPEpwvv/+e02ePNnhvkGDBqlDhw5ZmhQAAAAAeMKjVPHTTz912G6M0ZQpU7I0IQAAACDXsAT830pq2blRwfEatyo4195b88/7bKxWq1auXKmSJUt6Z2YAAAAA4Ca3Epzg4GCHX1/r1VdfzdqMAAAAAMBDbiU4S5culSS1bt3a9vVVwcHBqlChgsqVK+e92QEAAAA5yVdLOLNMtNe4leDExcVJkqZPn277GgAAAAByC4/uZurbt6+35wEAAADkPleXifbFBq/w6EyWL19e+/bt8/ZcAAAAACBLPEpwRo8erUGDBmnr1q2ZVlMDAAAA/MbVe3B8scErPHrQ56BBg5SRkaG6devKYrEoIMA+TyLpAQAAAJATPEpw5s+f7+15AAAAALnP1Qdx+mIceIVHCU6HDh28PQ8AAAAAyDKPEhwAAAAgPzAWi4wP7o/xxRj5hccJzrx58/Tdd9/p77//znTPzcqVK7M8MQAAAABwl0cX+02aNEn9+vVTkSJFtGzZMsXGxiokJES///67atSo4e05AgAAAIBLPEpw3n33XX333XeaMGGCJOn111/XkiVLNGbMGCUmJnpzfgAAAEDOsVh89KBPLlHzFo8SnP379ys2NlaSFBoaqnPnzkmSHnvsMS1ZssR7swMAAAAAN3iU4Fy+fFmhoaGSpHLlymnz5s2SpJMnT8pC9gkAAAB/4ZPqzf/f4BVZXkWtb9++6tWrl+6++279+uuv6tixozfmBQAAAABu8yjB2bNnj+3r0aNHq0iRIvrjjz/0wAMP6LnnnvPa5AAAAICcxDLReY9HCU7VqlVtXwcEBOipp57SU0895bVJAQDgry6Ygg7bC1jO+3gmAOCfPL5ELS0tTTNnztSOHTskSbVq1VK3bt0UEhLitckBAAAAOcpX98dwD47XeJTgbNmyRR07dlRiYqJq1qwpSXr77bc1fPhwLViwQLVr1/bqJAEAAABktn//fqWlpal69eoKCLhxknT58mXt27dPxYoVU7FixTLt37p1qy5dumTXVrJkScXExHhtztnNowTnkUceUYsWLfTBBx8oMjJSkpSSkqLHHntMDz/8sFatWuXVSQIAAAA5wmLxzTNq3Bzj4MGD6tatm/bv36+wsDCFhYXp22+/VePGjR32P336tEaPHq1p06apdOnSOnr0qBo0aKAvvvhCFStWtPXr2rWrLl++rOLFi9va+vTpo2effdajl5UTPEpwNm3apDlz5tiSG0mKjIzUW2+9pQoVKnhtcgAAAAAy69Onj4oVK6Y1a9YoKChIjz76qLp166Y9e/YoPDw8U/8DBw6oVq1aSkhIUFhYmFJSUtS5c2f16dMnU3FixIgRGjx4sK9eio4cOaKSJUsqKChIycnJmjx5siIjI9W/f38FBwe7Hc+ji/0qVqyoM2fOZGpPTExUpUqVPAkJAEC+UMBy3uEGIJcKCPDd5qJt27bpjz/+0Isvvqjg4GBZLBa9/PLLOnr0qH766SeHxzRq1EhDhgxRWFiYpCvFiYceekirV69WamqqXd+UlBRt2bJFSUlJHp82Vy1btkwPPvigAgMDJUn33nuvxo8fr5deesnjJMujBGfo0KHq3bu3li9frgsXLujChQtavny5evfuraFDh3o0EQAAAAA3tmHDBknSrbfeamsrU6aMypUrZ9vnik2bNql06dIKDQ21a3/ppZfUs2dPlSpVSm3bttXBgwe9Mm9HJk6cqCeeeEIWi0VHjhzR77//rq1bt2rz5s2aMWOGLly44HZMjxKcRx99VBs3blSrVq1UsGBBFSxYUK1atdKmTZv0yCOPKCgoyLYBAAAAcE1ycrLd9s/qinTlfprw8PBMl6IVK1ZMp0+fdmmc1atXa+LEiXrhhRfs2ocOHaozZ85o586dio+PV2pqqrp3766MjAzPX9R1HDp0SGXLlpUkLV26VC1btlSRIkVUsmRJlSpVSsePH3c7pkcZyPz58z05DAAAAMhTfP2gz3+uVjZ69Gi9/PLLdm3BwcG6fPmyjDGyXDO3ixcvunTPytatW9WpUycNHDhQQ4YMsdt37WVhxYsX1//+9z81b95cO3bsUJ06ddx9WTdUuXJlzZ49W/Xr19fnn3+ujh07Srqy2ltCQoLKlSvndkyPEpwOHTp4chgAAACA64iPj1dUVJTt+39ePiZJ5cuXV3p6uk6cOKGSJUtKkowxOn78uMqXL3/d+Nu3b1fbtm11zz33aNKkSTecT5kyZSRJhw8fzpYEZ+jQobr99tv1+uuvKyYmRg8++KAkaerUqbrvvvs8esYm15ABAAAAzvj4QZ9RUVF2CY4jsbGxCgkJ0YIFCzRw4EBJ0ooVK5SUlKS2bdva+m3ZskWFChWyVYV27NihNm3aqHPnzvroo4/sqj+SdOnSJdsiBFctXrxYFovF9uxLb6tWrZr27t2rffv2qU6dOoqIiJAk1axZU3FxccrIyLAtQOAqEhwAAAAgDylcuLCee+45DR06VMHBwYqIiNDQoUPVo0cPNWjQwNavU6dO6tq1qyZMmKADBw6oTZs2qlatmh555BH9+eeftn716tVTSEiIVq1apddff139+vVTTEyM1qxZo9dee02PPfaY3bNyvCk2NlbffPONmjZtatfevHlz1alTR998843blSMSHAAAAMAJYwmQ8UEFx90xXnvtNZUrV05Tp05VWlqaBg4cqH//+992ferVq2e7ZG3Pnj0qW7asLl68qMcee8yu37x581S6dGm1adNGISEhmjx5sg4cOGCL37Vr1yy9Nk9dvHjR4TN9bsRijDHZMJ9cJTk5WdHR0dq0cYPdw0kBAACQs1JSUlS/QUOdPXv2hpdm+dLVz49HFk1XVMEC2T/e+Qsqe3vvXHcessvHH3+sEydOaOLEibrvvvtUokQJ2z5jjA4ePKhZs2YpISHB7ftwslTBSUxMVGJiYqb2qlWrZiUsAAAAkDtYLFc2X4yTjyxbtkz79u1TSkqKli1bZlepCQwMVKlSpTRr1izfLTLw559/6v7779fOnTsd7s8HRSEAAAAAHvrqq68kSY8//riGDRt2w9Xf3OFRgjN48GA1atRIX3/9tQoXLuy1yQAAAAC5iZGP7sGRD1Zqy4Xef/99r8f0KMHZvn27Fi1apOjoaG/PBwAAAIAfmzRpkk6cOKEhQ4bo+++/14kTJ5z2HTJkiN39Oa7wKMGpVKmSzpw5Q4IDAAAA/8Y9OF63evVq7d+/X/369bN97Uy/fv3cju9RgjNs2DANHjxYH3zwgSpVquRJCAAAAAD50NSpUx1+7S0eJTgDBgxQRkaGKleurICAgExPQU1PT/fK5AAAAADAHR4lOPPnz/f2PAAAAIDcx2KRfLDIQH66RO2fVq5cqZ9++kknTpzItBrzq6++qjJlyrgVz6MEp0OHDp4cBgAAAAA2X331lR588EE1b97cYSJjtVrdjulygnPp0iVJUlhYmO1rZ8LCwtyeCAAAAJDbGItFxgfVFV+MkRtNmTJF7777rh5//HGvxXQ5wbn6dFFjjN2TRh3hQZ8AAAAAbiQjI0ONGjXyakyXE5wVK1Y4/BoAAADwW5YAH92Dkz8f9NmqVSstXLhQTZo08VpMlxOc2NhYh197y++//65p06apbdu26tmzp92+I0eOaOrUqUpISFDdunX1wAMPKCQkxOtzAAAAAOA7pUuX1tNPP63t27erfv36CgqyT08GDBigokWLuhXTo0UGrkpMTFRiYmKm9qpVq7oV59SpU7r//vuVnJyssLAwuwRn586duu222xQbG6smTZrojTfe0BdffKElS5ZkOgEAAACANxlZZOSDe3B8MEZutGjRItWsWVM7d+7Uzp07M+2/5557fJPg/Pnnn7r//vsdTkJy/x6c/v37a/DgwZo+fXqmfcOGDdPNN9+sOXPmyGKxaMCAAapUqZK+/PJL9e/f35PpAwDgFiPHl45Y5P7qPueskQ7bIwJS3I4FAHnd999/7/WYHl3sN3jwYDVq1EgbNmzQgQMHMm3uePvtt3Xu3Dk999xzmfZdvnxZP//8s3r37m17mGiZMmXUunVrzZ0715OpAwAAAC4zlgCfbfAOjyo427dv16JFixQdHZ2lwf/880+9/vrrWrdunQICMr+phw4dUlpamipVqmTXXqlSJf3+++9O46ampio1NdX2fXJycpbmCQAAAMD7JkyYoOPHjzvd/8wzz6hkyZJuxfQowalUqZLOnDmTpQTn3Llz6tWrl959912VL1/eYZ+LFy9KkiIj7cv5UVFRunDhgtPYY8eO1SuvvOLx3AAAAABJrKKWzbZt25bpCrAjR45o586datiwoQYPHux2TI8SnGHDhmnw4MH64IMPMlVXXPXll1/q1KlTWrp0qZYuXSpJOnz4sJYsWaLBgwdr0qRJioqKkiQlJSXZHXvmzBnbPkdGjBihZ5991vZ9cnKyYmJiPJonAAAAgOzxySefOGyfPHmy5syZo4oVK7od0+UE558rlmVkZKhy5coKCAiw3R9zVXp6+g3jtWjRQmPHjrVrW7BggYoXL6769evLYrEoJiZGkZGR2r59uzp06GDrt337dtWuXdtp7NDQUIWGhrrysgAAAADkMoMGDdKoUaN07tw5RUREuHWsywnO/Pnz3Z7Y9dSuXTtTkvLhhx+qbt26tlKUxWLRvffeq88++0yDBw9WgQIF9Oeff2rVqlUaMWKEV+cDAMgfTqc7X260aNBph+2erJbmzN83tXTYXmvXAq+NAcB7jMUiY/HBMtE+GCMvSUtL06VLl3TmzJnsS3CuraAMGjRIkydPdthv0KBBdn2zauzYsWrdurUaNGigm2++Wb/++qsefvhh3X333V4bAwAAAIDvzZkzR2fOnLFrO3/+vGbOnKkSJUqoXLlybsf06B6cTz/91GGCY4zRlClTnCY/N/Liiy+qTJkydm3FixfXhg0btGjRIiUkJGjYsGG65ZZbPIoPAAAAuMNXSzjn12WiJ06cmOnZmhEREWrQoIE+/vjjTLfCuMKtBOfae2v+eZ+N1WrVypUr3V7G7Vo9evRw2B4SEqK77rrL47gAAAAAcp9FixZ5PaZbCU5wcLDDr6/16quvZm1GAAAAQG5hsVzZfDEOvMKtBOfqcs6tW7e2fX1VcHCwKlSo4NF1cgAAAADgDW4lOHFxcZKkLVu2qE6dOtkxHwAAspWzldJ8hdXSgDzGR/fg5NcHfWYHlxOcS5cuSZLCwsJUtWpV2/eOhIWFZX1mAAAAAOAmlxOc8PBwSVdWSrv6tTPGmKzNCgAAAMgFjCwy8sFzcHwwRn7hcoKzYsUKh18DAAAAgKe2bNmit956S7t379bUqVNVpUoVffPNN2rYsKGqV6/udjyXE5zY2Fjb15GRkapXr55H61IDAAAAeQXPwclemzZt0m233aZ7771Xe/fu1cWLFyVJhQoV0tChQzV37ly3Y3p0Jhs0aKBixYrpnnvu0TvvvKPNmzdzWRoAwG8ZBTjcAABZ87///U+vvvqqPv/8c5UoUcLW3q5dOy1dulRnzpxxO6ZH/zqfOnVKkydPVvny5TVlypRMCQ8AAAAA3MiePXvUqlUrSbK7OiwgIEBFihTRqVOn3I7pUYJTpEgRu+rNnj171KlTJ82bN09PP/20JyEBAACA3Mei/3vYZ7ZuOf1Cc0bx4sW1d+9eSfYJzp49e3T8+HGVKVPG7ZhuPQfnqrNnz2rFihVaunSpfvvtN23ZskV169bVU089ZXtWDgAAAABcz4ABA/T888+rVKlSslqtOnv2rObPn6+hQ4fqvvvuU8GCBd2O6VGCU7RoURUuXFgPPvigXn75ZbVs2VLR0dGehAIAAAByLV/dc5df7+vr2bOnDh06pI4dO+rChQu2hc06deqk9957z6OYHiU4HTt21PLlyzVt2jTFx8fr8OHDiouL00033eTRJAAAAADkT0OHDtWjjz6qP//8UxcvXlT16tVVpUoVj+N5lODMnj1bVqtVmzdv1m+//aaff/5ZL7zwgkJDQxUXF6fp06d7PCEA8BchGZec7ksLDPPaOM7+6meR1Wtj5FaHLjq/Nnvs6zsdtn/wSiGnx3jznGU4+S+2wLvDHLafeWKC01gFLOcdtj/1v8tOjxn2VDmH7WVCE5we48zZjEIO26MDk9yOBeQ1xmKR8cGjUXwxRm7UoEEDffnll6pdu7bXbnXxKMGRrqxsUL9+fQUFBSkwMFCStGDBAs2YMYMEBwAAAMANFSlSRCdOnFDt2rW9FtOji/3ee+899ejRQ8WLF9fNN9+sjz76SOXKldP06dOVkOD+X4YAAACA3Ojqgz59seVHDz30kF5//XWdPXvWazE9quB8+OGHatWqlT744APFxcWpePHiXpsQAAAAgPzh559/1tKlS1W2bFlVr15dBQoUsNs/bdo0VapUya2YHiU4W7du9eQwAAAAIE8xssj44CE1vhgjN2ratKkqV67sdL/PlokGAAAAgKwaMmSI12OS4ABANvHmSmnXkx9WS3OmQvhRp/s+fCXKyR73z5cn5zhQ6Q7bU58c47C9gByvlHY97zwffJ293rsnltXSkJ/56v6Y/HoPzj8ZY2TJ4opynEkAAAAAOWblypVq06aNChcurLCwMNWqVUvvvvuu0tMd/6HoRjyq4GRkZNiWhv6n5ORkRUU5+6sZAAAAAFyxdOlStW/fXj169NBbb72lAgUKaMuWLXr11Ve1c+dOTZo0ye2YHlVwWrZsqQMHDmRq//3331W/fn1PQgIAAAC5ztUHffpiy48mTJigkSNH6uuvv9aAAQN033336T//+Y+WLVumTz/9VCkpKW7H9CjBKVq0qOrXr69p06ZJktLT0zVq1CjFxcWpc+fOnoQEAAAAkM/Ex8erffv2mdpr166tkiVL6tixY27H9OgStblz52rSpEl69NFHtWDBAh04cEDx8fFasGCB2rVr50lIAAAAINdhmejsVaFCBf30009q1qyZXftff/2lEydOqEyZMm7H9HgVtSFDhujw4cMaO3asAgMDtWzZMjVv3tzTcAAAAADymWeffVa33367du7cqbZt2yo8PFxbt27V5MmTNXjwYEVERLgd06NL1JKSknTvvffq3Xff1Xvvvafu3burXbt2+vjjjz0JBwAAAORKV5eJ9sWWH7Vo0UIrVqzQuXPnNHr0aD3++OP69ddfNXbsWL355psexfSoglOvXj2VKFFCGzZsUPXq1fX444/riy++0BNPPKEFCxZozpw5Hk0GAAAAQP7SuHFj/fjjj16L51Gq2Lt3b/3xxx+qXr26ra1fv37avHmzTp065bXJAQAAADnp6j04vtjyq5SUFFmt9g9UPnfunDIyMjyK51GCM27cOAUHZ356cqVKlbR8+XKPJgIAAAAgf/n999/VsWNHGWPs2idPnqznnnvOo5geLzJw5MgRff/999q/f7/eeecdSdKSJUvUokULpw8BBQAgvzNO/rZokdVhuyexJOnQhdIO2ysWOOL2OA887fiYaRPKuh0LyGuMfHN/zPV+n/3ZG2+8oX//+9+Z8ocnnnhCxYoV05gxYxQeHu5WTI/O5Nq1a1WrVi199dVXevfdd23ts2fP1uTJkz0JCQAAACCfOXz4sAoVKpSpPTAwUGFhYTp69KjbMT1KcJ577jm99tprWrt2rV37ww8/rIkTJ3oSEgAAAMh1uAcne9WrV09ffvllpvZff/1V58+fV0xMjNsxPbpEbcOGDVqwYIEkyWL5vzejcuXK2rt3rychAQAAAOQz//73v9W4cWMdPnxYHTt2VIECBbRx40Z98sknGjVqlEJCQtyO6VEFJzQ0VGfOnMnUvnXrVhUvXtyTkAAAAABcZLVa9f77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/etf/7K1Pfroo0pLS9P8+fMdHlOtWjW75EaS2rdvr/379ys1NdWufevWrfrss8+0aNEinTt3zq25JSUlyWKxqEiRIipatKiKFSvm9J58V3ktwdmwYYOGDBmi0qVLu9T/1KlTunTpkk6ePKnKlSurbt26KliwoAYOHKjz589Lkk6ePCkpc5mrWLFitn2OpKamKjk52W4DAAAAcrt/fob9ZzLhiW3btkmSbrrpJltbVFSUypYta9vnivnz56tWrVoKDQ21tVksFv3xxx9avHixnnjiCdWsWVMrVqxwOeavv/6qPXv2qH///jpw4IAefPBBFS5cWHfccYfGjBnj0ef4LN2Dk5SUpK+++kqTJ0/W1q1b1bJlS7322msuHXv1uTpTpkzR8uXLVaNGDe3bt08tW7bUyJEj9c4779hWS0tPT7c79vLlywoMDHQae+zYsXrllVc8fFUAAADAFVZzZfPFOJIy3fg/evRovfzyy5n6f/nll9etlkRGRtrur0lOTlbBggUVHBxs16dw4cIuJxDTpk3TjBkztGDBArv2zz//XM2bN5ckZWRkaMCAAerdu7f27t3r8irMMTExevDBB/Xggw9q27Ztmjp1qt5//30tWrRIXbp0yf5FBowxWrZsmSZPnqyZM2eqatWq2rp1q86cOaNChQq5HKd48eIKDQ1V7969VaNGDUlSlSpV9MADD+iHH36QJJUrV06SdPz4cbtjjx8/rrJlyzqNPWLECD377LO275OTk11aJQIAAADISfHx8Xb34FxbLbnWtm3bdObMGadxrr0CKjw8XBcuXFBGRoZdkSA5OVkFChS44ZzmzJmjQYMGadKkSerQoYPdvqvJjSQFBgbqueee07Rp07RlyxbdeuutN4y9e/duLV68WEuXLtWyZct04sQJ1ahRQ/fff7/i4uJUtWrVG8b4J7cSnLFjx+rTTz/VsWPH1LNnTy1evFi33XabLBaLW8mNdOUEtGzZMtOycklJSbaFACIjI9WwYUMtXLhQ9913n6Qr1ZvFixfrqaeecho7NDTU6Q8DAAAA4DIfPQdH/3+MqKgolxYZGDt2rMuhq1WrJmOMDh06pMqVK0u6ckvH0aNHb5hAzJ07V/fdd5/efvttPfroozcc62rV5nrJ17W6d++uy5cvKy4uTu+8845at26tkiVLunSsM24lOCNHjlSTJk20bNmy61ZQXDV69Gi1b99et912m5o3b641a9boiy++0MSJE219Ro0apR49euiWW25Rs2bN9OabbyowMFCPPfZYlscHAAAA/F3z5s1VpEgRff3113rxxRclST/88INSU1N111132fp99dVXqlSpkm2Br/nz5+vee+/VW2+9pSFDhmSKe/z4cUVGRtotCvD1118rNDRUt9xyi0tzW7lypaKjo7Py8jJxK8F55ZVX9Nlnn+mmm25S79699cgjj7g8eUeaN2+uefPm6fXXX9ebb76p8uXL64svvtC9995r69OlSxd98803euedd/Tuu++qbt26Wr58uYoVK+bxuAAAAEB+ERYWpgkTJuihhx7SyZMnFRERoYkTJ2rEiBGqWLGird8LL7ygrl276rbbbtOff/6pHj16qFGjRgoICNCHH35o69e3b19FRkbqyJEjevDBB9WuXTvFxMRozZo1mjNnjiZMmODys3C8ndxIHjwHxxijRYsWafLkyZo9e7Zq166tjRs3un0Pji/xHBwAAIDcKbc/B+e7ZadUwAfPwblwLlk9WxXL1vOwbt06zZo1S2lpaWrXrp3at29vt/+FF15Q/fr11bNnT61fv16TJ092GGfMmDG2BObkyZOaMWOGDhw4oHLlyqlLly62y+BySpYe9Hn69GlNmzZNn376qXbt2qVWrVqpa9euevzxx705xywjwQEAAMidSHCu8EWCk19k6Tk4RYsW1dNPP60tW7ZoxYoVqlixokaMGOGtuQEAAAA5yiqLzzZ4h9ce9NmkSRN98sknOnbsmLdCAgAAAIBbsvSgT0euXUUBAAAAyMuMubL5Yhx4h9cqOAAAAACQ07xewQEAAAD8hfHRgz598jDRfIIKDgAAAAC/4XEFJz4+XuvWrVNiYmKmfYMGDcrSpAAAAIDcwGqubL4YB97hUYLz5Zdf6qGHHlJ4eLjDh3uS4AAAAADICR4lOKNGjdJbb72V6x7oCQAAAHgTq6jlPR7dg3Pq1CkNGDDA23MBAAAAgCzxKMG5+eabtWXLFm/PBQAAAACyxKNL1Lp166bevXvrpZdeUtWqVWWx2C9rFxsb65XJAQAAADnJyCIjHywT7YMx8guPEpxnn31WkjRw4ECH+w0XEQIAAADIAR4lOBcvXvT2PAAAAIBcxyofLROd/UPkGx4lOGFhYd6eBwAAAABkmcsJzs8//yxJ6tChg+1r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r16maNGi5u+//865iSPLDhw4YKKjo02XLl3MggULzDfffGNq165tGjVqZNLS0mz9OnXqZKpXr25mzJhh3n//fRMeHm7eeuutHJw5gOxiMcbJo579TFJSksaNG6d169apcOHCGjRokNq3b5/T04KXDRkyRH/99Vem9ubNm2vcuHG2748fP67XX39dW7ZsUcmSJfX444+refPmvpwqslliYqI6d+6sN9980+4vtMYYff7555o5c6bS09PVvn17/etf/8q08ADynr///lv/+9//tHPnTpUqVUq9evVSx44d7fps27ZNb775pg4dOqQqVaro+eeft1tlEXnTwYMH9e6772rHjh0KCwtT48aN9a9//UuRkZG2PpcuXdLbb7+tpUuXKjw8XL169VLv3r1zcNYAsku+SXAAAAAA+L98cQ8OAAAAgPyBBAcAAACA3yDBAQAAAOA3SHAAAAAA+A0SHAAAAAB+gwQHAAAAgN8gwQEAAADgN0hwgHxq06ZNWrZsWZbjbN26VYsXL/bCjNznymvIjvm5e+68NYddu3bpl19+yXIcb1myZIm2bNly3T6//PKLduzYkeU4AAC4KiinJwAgZ3z55ZfaunWrWrVqlaU433//vRYtWqS2bdt6HGP37t3asGGD7fuIiAjVrFnzhk+Yd+U1eGN+noybHXOYN2+evvnmG7Vr1y5Lcbzl1VdfVWxsrOrWrStJWrx4sUqWLKk6derY+owcOVI9evTQTTfd5HKc3MjRawMA5E4kOACyxBsf+H788Uc9//zz6tatmyTp7NmzWr58ue655x5NnTpVAQF5u9jsrx+K27Rpo5o1a9q+Hz16tG6//Xa3X+8/4+RGnr42AIDvkeAAfm7Pnj3avn27KlSooPr162fan5qaqk2bNikxMVG33nqrihUrZtu3b98+rVu3TpIUGRmp2rVrq2LFinbH16xZU4ULF7Z9v2nTJp09e1ZNmzZ1GteRAgUK6JtvvrF9v2bNGjVt2lQDBw5UmzZtrnvsxYsXtXHjRp0+fVotWrRQoUKFrtvfGKN169bp8OHDqlixoho2bOiw343O3bWWLVum5ORkderUKdM+T89Renq6VqxYofT09OuOv3PnTu3cuVOlS5dWw4YNFRwcLEk6duyYli1bpvbt29vGN8Zo5syZqlmzZqYP63v27NG+ffvUoUMHSdKFCxc0d+5cNWjQ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SEimny93xgQAXB8JDuCHQkNDFR4ertOnT2cpzrPPPqvHH39cr7zyiq2tZs2aMsZkdYo3VKxYMTVt2lSLFy++boJz5swZh987WtQgKChIhQoVUmJiol17YmKirb+r565ly5a6+eab1bdvXy1ZskT16tVz6XW5IigoSNHR0U5fmyQFBwcrLCxM9913n4YMGXLdeO+//75OnTqlokWL6vXXX7e7h+qf4uLi9MYbb+jXX39V7dq1VaRIEcXFxem3337T+fPnFRcXl6XXlp0cna/IyEiFhobq9OnTGjFihBYvXqzWrVtLko4fP65vv/0208+zo/usPBEVFSVJeuWVV1SrVq3r9vXWmAAAHvQJ+K077rhD06ZNs/vwdurUKbeSk+PHj9tVQf766y/t2bPHq/N0xhijffv2qVSpUtftt2XLFu3bt8/2/axZs1SkSBGnyw7HxsZq1qxZduPMnDnT7qZuV8/duHHjNHDgQLVt29bhTftZERsba7uhXbpS1Zk7d67te4vFovbt22vy5MnKyMiwO/bIkSO2r7dv367nnntOkyZN0rRp0/Tmm29e9yGlt912m4wxev31123JzNWqzvLly6+b4ERERNywypKd5s+fr/T0dNv3s2bNUvPmzSVduTTNGGP38/z999+7HNuT19awYUOVKFFCH374YaZ9R48edSsWAMB1VHAAPzV+/Hi1aNFCt99+u3r06KGTJ0/qu+++0+bNm13+a3HXrl01cuRIJSUl6fz583r77bcVERGRLfO9fPmy7RK18+fPa/78+dq/f7+mTp163eOio6P1/9q7n1do1ziO459TUpQfsWQoQpI0mdSMUChZTEqkYZisZKEUSVM2SjJkYdhwbySa2AhlQX5OZkppMop/QU0TFpTNnMXpmc7g+eWc5zyd6f1a39d139fVvbi/3d/v9W1tbdXQ0JAikYhmZmY0NzcXT896a3p6WlarVQ6HQ42Njdrb29Pd3Z3W19fj1/zM3nk8HsViMTU1Neno6Ohfa1Y5OTkpm80ml8ul2tpabW5u6uHhIeEUsfn5eTU0NMhms8npdCoWi+ns7Eypqana2NjQ6+urenp61N7eru7ubknS8PCwent7dX19/eFx2l/qcPx+vyYmJiRJNTU1ikQien5+/mb9jcVikc/nU1lZmdLS0r5a6/OrPD4+qqWlRV1dXbq4uNDu7q78fr8kqbS0VOXl5XI4HHK5XLq9vf3uu/V3n1lbamqqDMNQZ2en7u/v1dzcrEgkop2dHfX19WlwcPCzSwUAfAMBDpCkSkpKFA6HZRiGgsGgiouLdXh4GC+UN5vN79K4iouLE/q4LC4uanl5WZeXl8rMzNTW1pYODg4S+qe87aXyI/O+VVZWJrvdHv9jkZ6erurqai0sLMhkMn11nNls1tjYmOrq6rS9va1oNCqfz5fw8fn2+SoqKhQKhWQYhs7Pz1VVVaWlpSXl5+d/eu9mZ2eVm5urlZUVeTyed31QPrNHZrNZwWBQhmEoFAqpv79fWVlZCgQC8WuKiooUDoe1urqqq6srZWdny+l0qq2tTZJ0fHysyspKeb3e+JipqSk9PT1pf39fDofjw30dGBhQXl6e6uvrJf2VDjc6OqpoNJpQf/O2Qafb7VZOTo7Ozs708vKi1tZWtbS0vEvPslqtCQc2vJ3nR8Z8ZGRkRIWFhfL7/crIyFAwGIz3D0pJSdHp6akWFxd1cnKigoICBQIBud3uhDV9dO9/sja73a6bmxutra3J7/fLZDLJ6/XKYrF8954AgM/5I/ZfJNMDAPALWSwWdXR0aHx8/Hc/CgDgN6MGBwAAAEDSIMABAPzvkeYFAPiCFDUAAAAASYM/OAAAAACSBgEOAAAAgKRBgAMAAAAgaRDgAAAAAEgaBDgAAAAAkgYBDgAAAICkQYADAAAAIGkQ4AAAAABIGgQ4AAAAAJLGn2IwWy9+nJoRAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "block_scorer = score_function.render_block_pair_scoring_module(pose_stack)\n", "weighted_by_term = block_scorer(pose_stack.coords, sum_terms=False, apply_weights=True)\n", "score_types = score_function.all_score_types()\n", "\n", "forward = weighted_by_term[:, 0][:, chain_a][:, :, chain_b]\n", "reverse = weighted_by_term[:, 0][:, chain_b][:, :, chain_a].transpose(1, 2)\n", "pair_by_term = forward + reverse\n", "all_term_interface = pair_by_term.sum(dim=(1, 2))\n", "\n", "chain_a_batch = chain_a.unsqueeze(0)\n", "chain_b_batch = chain_b.unsqueeze(0)\n", "helper_interface = calculate_block_pair_ddg(\n", " pose_stack,\n", " chain_a_batch,\n", " chain_b_batch,\n", " sfxn=score_function,\n", " sum_terms=False,\n", " minimize=False,\n", " pack=False,\n", ")[:, 0]\n", "torch.testing.assert_close(all_term_interface, helper_interface)\n", "\n", "nonbonded_types = [\n", " ScoreType.fa_ljatr,\n", " ScoreType.fa_ljrep,\n", " ScoreType.fa_lk,\n", " ScoreType.fa_elec,\n", " ScoreType.hbond,\n", "]\n", "nonbonded_indices = [score_types.index(term) for term in nonbonded_types]\n", "nonbonded_pairs = pair_by_term[nonbonded_indices].sum(dim=0)\n", "\n", "chain_a_blocks = torch.nonzero(chain_a, as_tuple=False).flatten()\n", "chain_b_blocks = torch.nonzero(chain_b, as_tuple=False).flatten()\n", "chain_a_contributions = nonbonded_pairs.sum(dim=1)\n", "chain_b_contributions = nonbonded_pairs.sum(dim=0)\n", "\n", "\n", "def contribution_rows(blocks, contributions):\n", " rows = []\n", " for local_index, block_index_tensor in enumerate(blocks):\n", " block_index = int(block_index_tensor)\n", " rows.append(\n", " {\n", " \"block_index\": block_index,\n", " \"author_label\": block_label(pose_stack, block_index),\n", " \"identity\": pose_stack.block_type(0, block_index).name3,\n", " \"five_term_interface_score\": float(\n", " contributions[local_index].detach().cpu()\n", " ),\n", " }\n", " )\n", " return rows\n", "\n", "\n", "contribution_frame = pd.DataFrame(\n", " contribution_rows(chain_a_blocks, chain_a_contributions)\n", " + contribution_rows(chain_b_blocks, chain_b_contributions)\n", ").sort_values(\"five_term_interface_score\")\n", "show_table(contribution_frame.head(16))\n", "\n", "fig, ax = plt.subplots(figsize=(8.5, 6.5))\n", "image = ax.imshow(\n", " nonbonded_pairs.detach().cpu(),\n", " cmap=\"coolwarm\",\n", " aspect=\"auto\",\n", " vmin=-max(1.0, float(nonbonded_pairs.abs().quantile(0.99).detach().cpu())),\n", " vmax=max(1.0, float(nonbonded_pairs.abs().quantile(0.99).detach().cpu())),\n", ")\n", "ax.set(\n", " xlabel=\"chain B block index within partner\",\n", " ylabel=\"chain A block index within partner\",\n", " title=\"KcsA A–B nonbonded block-pair accounting\",\n", ")\n", "fig.colorbar(image, ax=ax, label=\"weighted score units\")\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "2c4ab8fc", "metadata": {}, "source": [ "**Expected observations.** Most of the dense matrix is near zero, while a\n", "limited band of cross-chain pairs carries the interface score. Summing both\n", "matrix orientations is essential: a single row or column can omit a stored\n", "interaction. The table includes both chains and uses author labels, so its\n", "rank does not depend on assuming that chain A occupies blocks 0–96.\n", "\n", "## Choose three native hotspots\n", "\n", "For a compact alanine-scan demonstration, select the three most favorable\n", "chain-A contributors that are internal residues and are not already alanine or\n", "glycine. This rule is stated in code rather than silently hard-coding residue\n", "numbers. It chooses sites from the native fixed-structure decomposition; the\n", "subsequent repacking experiment is a separate calculation." ] }, { "cell_type": "code", "execution_count": 5, "id": "9fe482d4", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", " \n", " \n", " \n", " \n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", "\n", "
block_indexauthor_labelidentityfive_term_interface_score
55A:78TYR-6.986693
80A:103PHE-4.636461
92A:115VAL-2.759967
\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "Orange hotspots: A:78, A:103, A:115\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": [ "chain_a_block_list = chain_a_blocks.detach().cpu().tolist()\n", "eligible = contribution_frame[\n", " (contribution_frame[\"author_label\"].str.startswith(\"A:\"))\n", " & ~contribution_frame[\"identity\"].isin({\"ALA\", \"GLY\"})\n", " & contribution_frame[\"block_index\"].isin(chain_a_block_list[1:-1])\n", "]\n", "hotspot_frame = eligible.head(3).copy().reset_index(drop=True)\n", "hotspot_blocks = hotspot_frame[\"block_index\"].astype(int).tolist()\n", "assert len(hotspot_blocks) == 3\n", "show_table(hotspot_frame)\n", "\n", "hotspot_mask = torch.zeros_like(chain_a)\n", "hotspot_mask[hotspot_blocks] = True\n", "hotspot_atoms = res_mask_to_coord_mask(pose_stack, hotspot_mask.unsqueeze(0))\n", "try:\n", " hotspot_viewer = tmol.view(\n", " pose_stack,\n", " highlighted=hotspot_atoms[pose_stack.real_atoms],\n", " highlight_color=\"#f97316\",\n", " )\n", " print(\"Orange hotspots: \" + \", \".join(hotspot_frame[\"author_label\"].tolist()))\n", " hotspot_viewer.show()\n", "except ImportError as exc:\n", " print(\"Interactive hotspot viewer unavailable:\", exc)" ] }, { "cell_type": "markdown", "id": "69a6d9af", "metadata": {}, "source": [ "## Test alanine substitutions in one packing batch\n", "\n", "Each site contributes two batch members: an independently repacked WT control\n", "and an alanine variant. Both use the same geometry-defined local packing shell.\n", "All blocks outside that shell remain fixed, every non-target block retains its\n", "identity, and the mutation target is restricted to alanine in only its mutant\n", "member.\n", "\n", "`compute_block_adjacency()` uses enclosing residue spheres plus a 5 Å gap, so\n", "the shell is deliberately conservative rather than an exact atom-contact set.\n", "The batch exposes independent site/state work to one packer call. One outcome\n", "per state is enough to demonstrate the API, but not to estimate sampling\n", "uncertainty or establish convergence." ] }, { "cell_type": "code", "execution_count": 6, "id": "0da51df3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "packed 6 site/state members in 4.412 s; shell sizes=[41, 41, 41, 41, 24, 24]\n" ] } ], "source": [ "requests = [\n", " (block_index, state)\n", " for block_index in hotspot_blocks\n", " for state in (\"repacked WT\", \"ALA\")\n", "]\n", "scan_batch = PoseStackBuilder.from_poses([pose_stack] * len(requests), device)\n", "scan_task = PackerTask(scan_batch, PackerPalette())\n", "\n", "mutation_mask = torch.zeros_like(scan_batch.block_type_ind, dtype=torch.bool)\n", "for pose_index, (block_index, state) in enumerate(requests):\n", " if state == \"ALA\":\n", " mutation_mask[pose_index, block_index] = True\n", "\n", "# Restrictions only remove choices. Preserve the original identity everywhere\n", "# except mutant targets, then restrict those targets to alanine.\n", "scan_task.restrict_to_repacking(~mutation_mask)\n", "scan_task.restrict_absent_name3s({\"ALA\"}, mutation_mask)\n", "\n", "centroids, radii = compute_block_centroids_and_furthest_dist(pose_stack)\n", "adjacency = compute_block_adjacency(centroids, radii)\n", "packing_shells = torch.zeros_like(scan_batch.block_type_ind, dtype=torch.bool)\n", "for pose_index, (block_index, _) in enumerate(requests):\n", " packing_shells[pose_index] = adjacency[0, block_index]\n", " packing_shells[pose_index, block_index] = True\n", "scan_task.disable_packing_by_block_mask(~packing_shells)\n", "\n", "scan_task.add_conformer_sampler(create_dunbrack_sampler_from_database(param_db, device))\n", "scan_task.add_conformer_sampler(FixedAAChiSampler())\n", "scan_task.add_conformer_sampler(IncludeCurrentSampler())\n", "\n", "torch.manual_seed(SEED) # Controls CUDA annealing, not the CPU C RNG stream.\n", "if device.type == \"cuda\":\n", " torch.cuda.synchronize()\n", "scan_start = perf_counter()\n", "packed_scan = pack_rotamers(scan_batch, score_function, scan_task)\n", "if device.type == \"cuda\":\n", " torch.cuda.synchronize()\n", "scan_seconds = perf_counter() - scan_start\n", "\n", "for pose_index, (target_block, state) in enumerate(requests):\n", " expected = \"ALA\" if state == \"ALA\" else pose_stack.block_type(0, target_block).name3\n", " assert packed_scan.block_type(pose_index, target_block).name3 == expected\n", " for block_index in range(pose_stack.max_n_blocks):\n", " if block_index != target_block:\n", " assert (\n", " packed_scan.block_type(pose_index, block_index).name3\n", " == pose_stack.block_type(0, block_index).name3\n", " )\n", "\n", "print(\n", " f\"packed {len(requests)} site/state members in {scan_seconds:.3f} s; \"\n", " f\"shell sizes={packing_shells.sum(dim=1).detach().cpu().tolist()}\"\n", ")" ] }, { "cell_type": "markdown", "id": "c131b920", "metadata": {}, "source": [ "## Compare matched site/state calculations\n", "\n", "The interface score sums all weighted terms crossing chain A and chain B. The\n", "target-to-partner score uses one integer target block per batch member and\n", "chain B as its partner mask; this indexed reduction avoids constructing a\n", "dense target mask. Whole-pose totals provide a third diagnostic. Every mutant\n", "value is compared only with the independently repacked WT member for the same\n", "site and shell.\n", "\n", "These are **one-complex score changes**, not binding or stability ΔΔGs. There\n", "is no separated state, unfolded state, membrane model, solvent correction,\n", "backbone relaxation, experimental calibration, or sampling ensemble." ] }, { "cell_type": "code", "execution_count": 7, "id": "b448dfd5", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", " \n", " \n", " \n", " \n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", "\n", "
sitemutationpacking_shell_blocksinterface_score_change_non_ddgtarget_partner_score_change_non_ddgwhole_pose_score_change_non_ddg
1A:103PHE→ALA416.7020621.5888531.831299
0A:78TYR→ALA414.8426305.237190-4.357910
2A:115VAL→ALA241.0145001.0145011.229614
\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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fqndu3frkUce0ebNm3X+/HnFxMToxx9/VJMmTRz2W+HChTVr1iwtWrRIZ8+eVXR0tAYNGqTatWtb1yMWLlxYDRs21Geffab169db2+LTTz9VlSpVHOb+/PPPdeTIET388MPaunWrzp07py1btujxxx/P8pqzKlWqaNWqVUpPT1ejRo30559/5tp2eO+997R69Wq9/PLLOnHihA4fPqwnn3wy07Wc2XFmXT788ENt375dAwYMUExMjI4fP66XXnpJ0dHRGj16dKawdaNye3/lxLp169SlSxctXbpUp06dUlJSkubPn68//vhDTZo0sfrl9jZxdl4A9kLQA4BcMmDAAL377rsaM2aMihYtqh49eujZZ5/Vfffd59DP19dXX331lVauXKnAwECH5+j5+Pho+fLl6tGjh1588UWVKFFC4eHh+vvvv/Xoo4/muCZvb28tW7ZMvXv31vDhw1W6dGmVL19ezz//vKpXr65HHnlE0qXT7FasWKFSpUqpYcOGKleunNatW6cPPvjgurdHUFCQ1qxZo3r16ql9+/YKCgrSs88+q379+mnevHlyd3d3ep2d3ba5pUGDBtq4caN8fX3Vpk0bBQYGqnHjxvr+++81YsQI66isdOnoz+eff66vvvpKpUqVUseOHfXAAw9o4cKFDkeAp02bprp166pFixYKCQnRlClTNG3aNHl4eDjM3ahRI61bt07e3t5q2rSpihUrpr59+6pZs2YKDQ3Nst477rhDq1atUuHChdW4cWNt3rw5V7ZDt27d9P333+uXX35RmTJl1KxZMz3wwAPWdr9W4HBmXTp16qT58+dr9+7dqly5ssqVK6cVK1Zo5syZ6tevX66sx+Vye3/lRJ06dRQREaEPPvhAVatWVbFixfTSSy/ptdde09ixY61+ub1NnJ0XgL24mSvPCwAAAE7p27evfvrpJ4ebY9wOhgwZoqioKCUmJlqB/VZwu+4vALenW+e3MwAAcLnU1FTNnTtXjRo1uqVCHgDcbvgNDQAAsnTixAn16dNHmzdv1rlz57Rz505FREToyJEjGj58uKvLAwBcBUEPAABkqXjx4mrcuLEGDhyoEiVKqH79+oqPj9fixYvVqFEjV5cHALgKrtEDAAAAAJvhiB4AAAAA2AxBDwAAAABsJr+rC7Cz9PR0HT16VH5+fnJzc3N1OQAAAABuYcYYnT17VsHB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GzbUuHHjlJaWJunSEa933nlHO3futOr49ttvr7k+mzZtUufOnVWxYkU1adJE8+ZlPpIaGRmpsLAw3XXXXRo4cKASEhKs937++WdrvkqVKqlDhw7avHmzw/LTpk3To48+ar3OOCX0auNmJ2OuypUra/To0UpLS9O6deuuuZydcEQPAAAAyGUlS5bUxIkT1bp1ay1evFj+/v7y8fFRYGCgFThSUlK0Zs0a9e7dW76+vmrVqpUkKTk5WUeOHNEzzzyjTz75RJUqVVKxYsW0ZMkSPfHEExozZoyaNWumn3/+Wc8995zKli1rzbtp0yY1adJEb7/9tkaNGqWjR49q0KBBOnnypN577z21bt1aQ4YMcTh1s1ChQlddl99//11hYWEaOHCgXn/9dcXHx+vDDz9UgwYNVLhwYUn/H04//vhjJSUl6YknntCwYcP0+eefS5KaN29urffZs2f1ww8/KCwsTHv37lXx4sWt9stP3UxISNC8efPk4eGR7bjOmDNnjowxqlmzptPL2AFBDwAAAMhl+fLlU7FixSRJwcHBCgwMtN4LCQmx/l6uXDn98ccfmjRpkhX0Mnz66acO15W9//776t69u55++mlJ0l133aW1a9dqx44dVp8333xTffr0sfpUrlxZH3/8sTp27Kh3331XPj4+CggIUIECBRzquJo333xTzZo109ixY622sLAwGWOs1wEBAfr222/l5eUlSXr66ac1btw4631vb2+H+d566y0tWLBAs2fP1pNPPpnt3NcaNzsZcyUmJiopKUn//e9/de+99zq1vnZB0AMAAABuou+//14TJkzQwYMHlZSUpMTERFWqVClTv1q1ajm83rZtm7p06eLQ1rBhQ4egt2bNGq1du1azZ8+WMUbGGKWmpurcuXM6duyYgoODc1zv2rVr9c4772Rqd3Nzs/5evnx5K4xJUvHixXX69Gnr9YULF/TRRx/pl19+0bFjx3Tx4kXFxsbqwIEDV537WuNmJ+Po4fnz57VkyRI9++yzCg0NVfPmza+5rF0Q9AAAAICbZObMmRo4cKDGjx+vOnXqyN/fX+PHj8/yDpiXBxzp0qmeHh4eDm2enp4Ory9cuKDXX39dPXr0yDReximSV0pISNBdd92Vqb1v374aMWKELl68mGmeK+XLly9T2+VH/F544QUtW7ZMH3zwgSpUqCAfHx91795dycnJNzRudi4/enjnnXdq/vz5Gj16NEEPAAAAwI3JCCmXB5NFixapbdu2evzxx622gwcPOjVehQoVtH37doe2bdu2ObyuWrWqtm3bdtXTMvPly+dQk5+fX5Y3KvHz85N06RTR9evXq1+/fk7VmZVFixbpxRdf1EMPPSRJunjxov7+++9MRy3ziq+v7w0/uuFWw103AQAAgDyQcZrknj17rLaQkBCtX79ep0+fljFGM2fO1MyZM50ab8CAAYqMjNSGDRskSStXrtQPP/zg0Oell17StGnT9PXXXystLU3p6enatGmTXnjhBatPqVKldPjwYZ07d07SpVMwM+5SefmfgIAASdLzzz+vyZMna8aMGUpPT9f58+f19ttvKy4uzultERISoiVLlig1NVWpqal6+eWXdeTIEaeXvxGbNm3SvHnzbqujeRJBDwAAAMgTxYsX1zPPPKPw8HCVKlVKgwYN0rPPPquyZcsqODhYAQEBGjlyZKbr7rLTq1cv9ejRQ/fdd58CAwM1cOBARUREOJzO2blzZ02aNEmjRo1SwYIFrX4PPvig1adNmzaqUqWKihUr5tTjFSIiIjR+/Hg988wz8vPzU0hIiFJTU60g6Ixx48Zpy5YtKlSokAIDA7V79241aNDA6eVzKiOsBgUFKSwsTL169dKIESPybL5/IzfjzEmuuC4JCQkKCAhQfHy8/P39XV0OANw0Gb//qnxRRfm8M19fgWvb9vi2a3cCbhMXLlzQ/v37FRoamum6tVtBamqqTp06JS8vL+txBImJibp48aICAwOVmJio8+fPW3fpTElJ0cmTJ7M9/fL8+fNKS0uTn5+fnnnmGe3atUuLFi3K1O/MmTPy8fHJdpudP39ecXFxCgwMVMGCBa+5HsYYxcbGqnDhwnJ3///jRWfPntWFCxdUtGhRqy0pKUlxcXGZbv5y5swZeXl5ycfHR7GxscqfP78VGBMTE3Xu3DmHxy04O+7l63TmzBnrtZeXl4oUKXLNdfs3udrnPSf5gmv0AAAAgDxUoECBTMHE19fX4e+Xv/bw8Mgy5J0/f17jx4/XkCFD5Ofnp+joaEVFRenjjz/Oct6MUJkdHx8f+fj4OL0ebm5uWYYmPz8/63q+DN7e3vL29r5qTUFBQQ7vXbkdcjJuhpyuk50R9AAAAIBbgLe3txISEhQSEqKLFy+qQIECeu2119S7d29Xl4Z/IYIeAAAAcAtwc3PTu+++q3feeUf//POPChUq5OqS8C/GzVgAAACAW4ibmxshD9fEET0AQJ5Zd/Cw/D3dXF2Ga42Id3UFAIDbEEf0AAAAAMBmCHoAAAAAYDMEPQAAAACwmRwFvc2bN+v48eNZvpeSkqINGzbon3/+sdrS09O1YcMGHThwIMtlDhw4oD179uSkBKfk5rx79+7Vli1bcq84AAAAAMhjOQp6L7/8svr27ZvlezNnzlT9+vWVlJRktS1ZskR16tRRixYtslxmxIgRGjBgQE5KcEpuzZucnKx69eqpZs2a2rVrV26XCQAAAEiS/vrrL/Xt21cXL168oXFiYmLUt29fJSYm5lJluFXlKOj16dNHCxYs0NGjRzO9N2HCBD300EMqWbKk1RYZGamOHTvq4MGDWrly5Y1X66TcmnfWrFny8vJSeHi4IiMjc7FCAAAA4P8dP35cUVFRNxz0YmNjFRUVpQsXLuRSZbhV5ejxCh06dFBgYKAmT56sV155xWo/cOCA/ve//+mnn36y2k6fPq05c+Zo1apV8vLyUmRkpBo3bpxrhScmJsrX1zdTe27OGxkZqV69eqlGjRoaNGiQRo0aJQ8PjxstHQAAALllRMBNnIvHpeDWkaMjeh4eHurRo4cmTpzo0D5hwgSVKFFCDz30kNX2zTffqEqVKqpTp4769++vmTNnKiEhIVeK/uOPP1SuXDktWbIk03u5Ne/ff/+t5cuXq0+fPmrfvr3c3Nz0888/50b5AAAAuA28+eabio6Otl5/++236tevn5KTkyVJxhgNGjRIO3bssPrEx8dr/PjxevbZZ/X5558rJSXFYcyUlBRNnDhRgwcP1quvvqqNGzdesw5jjH7++Wc999xzGjZsmObPn3/V/hmnkZ44cULjxo3T008/rS+//FKpqak5ruW3337T66+/rueff16zZs26obqQMzm+62afPn20d+9erVixQtKlG59MmjRJjz/+uPLn//8DhFFRUerXr58kKSwsTKVLl9b333/v9Dznz5/Xhg0bsvyTkpKiIUOGqHXr1vrss88clrvReS8fp2nTpipXrpwKFCigJ5544pqnbyYnJyshIcHhDwAAAG5P+/fv15QpU6zX48aNU1RUlNatWydJ2rFjh7744gsVK1bM6hMWFqbDhw+rTJky+s9//qNu3bpZ76Wnp6tZs2YaPXq0Spcurfj4eNWvX1/Tp0/PtgZjjLp27apXX31VJUqUUGBgoJ588kkNHTo022UyTiOtW7euDhw4oODgYL333nvq3Llzjmr56aef1LRpU6WlpalMmTKaPn26Bg8efN11IWdydOqmJFWrVk316tXThAkTdP/992vRokWKiYlRnz59rD7r1q3Trl27VLlyZW3YsEGS1KRJE0VFRWngwIFOzXPw4MGr9jXG6OLFi3rnnXfUr18/eXh45Mq8kpSWlqbJkyerb9++1ji1atXSmDFjdOjQIZUpUybL5UaNGqWRI0c6PQ8AAADsKzw8XG+99ZYkKSEhQX/88Yc6duyo6OhohYWFadmyZbrrrrtUtGhR647wb7/9th555BFJUu3atRUWFqa4uDgVKlRI33//vTZu3Ki///5bxYsXlyQVLVpUzz33nNq3b5/lJUbTp0/X6tWrtWvXLvn5+UmSOnfurEqVKumpp55ShQoVsq3/qaee0ssvvyxJ6tSpk6pUqaLo6Gg1adLEqVpmzZqlnj17atSoUZKkZ555RocPH77huuCcHAc96dJRveeee07jx4/XhAkTFBYW5rAzIiMjVbJkSeuDkWHbtm3aunWr7rnnnmvOUaVKFStkXencuXN6/PHHrcO9GR/q3JhXkubPn69//vlHv/zyi3755RervUiRIpo4caLefPPNLJd75ZVXHP4XIiEhQaVLl3ZqTgAAANhLeHi4+vTpowMHDmj79u2qWrWqOnbsqK+++kqStGzZMoWHhzss06xZM+vvlSpVkiQdPnxYhQoV0rJly9S0aVMrWEnSY489ppEjR2rv3r2qWrVqphp++eUXeXh46MUXX5QxxvpToEABbd269aqBKiNwSlLFihVVs2ZNLV++XE2aNHGqlrvuukv//e9/NXv2bDVv3lx+fn4KCQm54brgnOsKet26ddPQoUP12Wefac6cOYqKirLeS0xM1LRp0zRz5sxMjzdo3769IiMjNX78+Bsq+sSJEwoODtaUKVPk4+OT6/NGRkaqR48e+uKLLxzaJ02apBEjRuiNN96Qu3vms149PT3l6el5nWsFAAAAOylXrpzKlCmj6Oho7dixQ+Hh4WrSpIl69+6tpKQkrVixQp9//rnDMt7e3tbf8+XLJ+nS2WaSdPLkSRUpUsShf8brEydOZBn0Tp8+rRIlSqh27doO7fXq1dPdd999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9eijjyo1NVVVqlRRWFjYDdcGAAAAAHktx49XqFixoj799FNJUlpamho1aqShQ4dqxYoVOZ788rFyU2RkpJ599llNmjRJP//8szp16nRd43zzzTeqUKGC7rnnHkVGRhL0AAAAANwSbugavXz58qlJkybauXNnbtXjlPT0dG3YsCHL9/766y+tXLlSgwcPVs+ePRUVFXXd80RFRalfv37q37+/Zs2apfh4njsEAAAA4N/vhh+Y/scff6hMmTLW6yNHjmQ6Svf3339nuWxWfatWraomTZpcdc6dO3fqoYce0tChQzVs2DCH96KiovTAAw8oNDRU/fv3V/Xq1RUTE6PSpUvnZLX022+/6a+//lKPHj1UuHBhlSlTRt99952eeuqpbJdJTk5WcnKy9TohISFHcwIAAABAbshx0MsIZxcvXtTq1au1cOFCzZo1y3r//Pnz2r17t8Myx44dy3KsrPoWLlxYknTq1ClNmzYt2zp69Oih1157TTt27NDkyZPl7u6uixcvavLkyfrkk08kSVWqVFGDBg00ceJEDR8+PEfrGRkZqU6dOln19OvXT5GRkVcNeqNGjdLIkSNzNA8AAAAA5LYcB72McFagQAHVr19fo0aNUoUKFaz3s7rubtWqVZo9e3amsa52jV5SUlKmEHi5jKNlf//9t9LT0+Xu7q5ff/1VJ06cUExMjDVusWLFNHHiRL3xxhtyc3Nzah3PnTunadOm6ZFHHrHGSUxM1ObNm7V582bVrFkzy+VeeeUVDR061KHGnB5JBAAAAIAbdUM3Y8lLZcqUyXaev//+W61bt1aPHj301VdfKX/+S6sRGRmphg0bat++fVbfkiVLKj4+XkuWLFHz5s2dmnvatGny9/eXt7e3Q9isVauWIiMj9dlnn2W5nKenpzw9PZ1dRQAAAADIEzd8jZ4rFCtWTG+88Ya6d+9utR07dkzz58/X6tWrVbduXYf+586dU1RUlNNBLyoqSj179tR7773n0D5nzhw98cQTGjNmjLy9vW98RQAAAAAgD7g06GV1MxYPDw/179//qsv5+vo6hDxJmjRpkooXL646depk6t++fXtFREQoNjZWQUFB2c59xx13qEKFClqzZo3Gjh2baZwHH3xQKSkp1sPfAQAAAODfKEdBr1mzZoqNjc3x+8HBwRo0aJAKFSrk0NfX1zfTdXjXe+qjh4eH3nnn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4kV5enqqQ4cOTtUj5WyfSJd+h2/YsEHHjh1T5cqVdeeddzq8n5KSonXr1uns2bOqW7euw2dRuhSo165dq4sXL6p+/fqZ3p8xY4YaNmyolJQUbdmyReXLl7f2ycmTJ/X777/Lx8dHtWrVsn4nZuXgwYPasmWLHn74YastLi5OCxcuVKdOnVSgQAEdP35cK1asUJcuXbRjxw7t379flStXdviZDgoKUvv27ZUvXz7Fx8frf//7nyRp+vTpcnd3V/ny5VWnTh0lJibq999/V2pqqu69914VKVLEGqNHjx569913dejQIZUpU+aa2xj4VzIAbitpaWkmIiLCREREmI4dO5py5cqZu+++2xw9etTqExMTYySZXbt2Ob3Mrl27jCTTrl07U61aNdO6dWvj4+NjXnzxxWzHdWYZY4z5/vvvTWBgoAkPDzctWrQwAQEB5quvvsp2HTPGDQsLM/fcc49p2bKlyZ8/vxk2bJjp2LGjqVmzpnnwwQeNp6en+eGHH26ovpUrVxpJJikpyWo7deqUkWQ2b95sjDFm//79pkyZMubuu+82bdu2NaGhoWb06NFZ1n6922jkyJHGy8vLNGvWzFSpUsW0atXKoQZntmPGXK1atTJ33nmnad68ufH29jYvvfRSjvaHK2rObq4LFy6YNm3aGEmmdevWJiIiwrzzzjuZtnOnTp1Mt27dHOpbt26dcXNzM/v27cu0nzLmbdOmjalSpYp55JFHzLp160xaWprp16+fKVKkiGndurWpVauWCQ0NNVu3brWWHTVqlClTpoypXr26uf/++02dOnWMr6+vWbRokcPcGT9zrVu3NgEBAaZv374ONVy8eNH07dvX+Pj4mKZNm5o6deqYpk2bmvPnz1vz3HvvvVb/qKgo4+/vb+bPn2/NERwcbGrXrm1at25tChcubJ577jmHOaZPn268vLxMw4YNTYMGDUzdunVNUFCQmThxYqZtYowx8fHxJl++fGbq1KlW2z333GNmz55tihYtarZs2WKMMSY1NdX4+vqaTz75JNMYERER5oEHHshy/Cs98MAD5oUXXrBejxs3zlSvXt16PXr0aCPJfPTRR1Zb5cqVzeeff+70NggKCnL4PfHdd98ZT09P06hRo2y3iaenp2nVqpUpX768adOmjSlWrJhp0aKFSU9PN8YY88wzz5gCBQqYhg0bmoiICNOvXz+n68npPklMTDQNGjQwZcuWNQ8//LC56667zKOPPmq9v2bNGlOqVClTsWJF06pVK1O2bFkzc+ZM6/25c+caPz8/U69ePdO4cWPj4+NjJk2a5DCHp6enadmypSlbtqzp0KGDmTZtmjHGmDFjxpiAgADz4IMPmvDwcFO4cGHz888/Z1mnMcZ88803pnjx4g5t69evN5JMXFycMcaY+fPnG3d3d9O6dWtTp04d06JFC+Ph4WHGjx9vLXP57+WYmBjTpEkTI8l06dLFREREmC+//NKsX7/eBAUFmXr16pnWrVubsmXLmilTpjjMHRISYr744ots6wX+7Qh6wG3u4sWLpk2bNmbgwIFW25Vfgp1ZJuOL75NPPml9mVmwYIFxd3c3x44dy3JcZ5bZvXu3KViwoFmzZo011+rVq42Xl1eWX8AvH3fQoEFW29ixY40k8/zzz1ttb7/9tqlYsWK26+1Mfc4EvWHDhpmmTZs6bL85c+ZkWfv11LB9+3bj7u5uBYW0tDTTsWNHhxqc2Y4Zc7Vu3dqkpqYaY4xZsWKFcXNzM7///nuOx7mZNV9trv379xtJZu/evdlu5wULFhgvLy/ry6QxxvTv3980adIky/2UMW+PHj2seY0x5j//+Y+pWrWq+eeff6y2YcOGOQSuUaNGGUkOXyCff/55U7ZsWZOSkpLlfEeOHDFBQUFmwYIFVtv7779vAgMDze7du6226Ohoa+7Lg94HH3xgChcubFavXm2MMebcuXOmRIkS5uuvv7aWPXz4sAkKCjJz5841xhiTkJBggoKCzIcffmj1efPNN42kbEOFMcbUrVvXDBgwwBhjzOnTp02+fPnM6dOnTadOnczYsWONMZfChSSzffv2TMvnJOgVKlTITJgwwXq9ZcsW4+bmZk6dOmWMMaZly5amdu3apm3btsYYY44fP24kmZ07dzq1DYxxDHrx8fGmUKFCDtvk7bffzrRNPD09TVhYmLlw4YIxxphDhw4ZDw8PhzAfEBBgZsyYYb3Oq30ydepUU7JkSasWY4yZPXu2McaYs2fPmmLFipmnnnrKpKWlGWMuBcPFixdb8xUrVsyMGDHCWvbTTz81BQsWNEeOHHFY3zp16phz585ZbUuXLjWFChUyf/75p0MthQsXNvHx8VnW6mzQk+Twn2X//e9/ja+vr7UOV/5ejo6ONpKs32vGGNO1a1fTu3dv63VSUpL59ddfHeZu1aqVQx/gVsPNWIDb1Pbt2zV37lzNmDFDxYsX1++//54rywwcONA6NSs8PFzp6en666+/rjru1Zb57rvvVKJECR05ckQzZszQ9OnTdfjwYfn5+Wn16tVXHXfAgAHW3zNO5bqybd++fUpLS7vu+pzh7e2tkydP6tixY5KkfPnyqV27dk4vf60aZsyYobvvvlvNmzeXJLm7u+uFF15wWD4n2/G5556zTstt3LixGjRooOnTp+d4nJtZ843uo+bNm6t48eL6/vvvJV26K+e0adPUu3fvqy43ePBgh1MlJ06cqLvvvluLFy+2ag4MDNTGjRuVkJBg9QsMDFS/fv2s1y+//LIOHDjg8DOVnJysNWvWaNasWVqxYoVCQkIc3p88ebL69u2rSpUqWW3h4eEKCAhwqPHll1/W2LFjtXz5ct13332SpAULFig2Nlb+/v6aOXOmZsyYodWrVys0NFTR0dGSLl1bl5iYqCFDhlhjvfDCC9e86UmTJk2sMZYvX66qVasqKChIYWFhVnt0dLSKFSuW5WnBzkpLS1NcXJwKFSpktd19990qXLiwli9frrS0NK1evVojRozQihUrlJaWpmXLlql48eKqUqWKU9vgSkuXLtX58+cdtsnQoUOta8Eu17t3b3l6ekqSSpcurXLlymnPnj3Zrk9e7RNvb2+dP39ee/futdoyThOdP3++Tp8+rVGjRlljFCxYUM2aNZMk/e9//9OZM2f04osvWssOHDhQXl5e+uWXXxzm6du3r3x8fKzXkyZNUuXKlbV161brZyE9PV3//POPtm7dmm29znryySetv4eHhysxMTFHdzr19vbWwYMHrbv8enl5qVWrVg59ChUqpNOnT99wrYCrcI0ecJs5d+6cHnroIe3cuVO1a9eWv7+/Dhw4oJMnT+bKMoULF7b+nvEl58KFC1et6WrLHDhwQBcuXNDMmTMdlmnatKnDF7ysXP5+xrhXtqWnpys1NTXLL2o3sk6Xe/rpp7V9+3aVL19e1apV04MPPqjBgwdb1ww542o1HDp0KNN1PFdeK5ST7ZjVWBl3PczJODez5hvdR+7u7urVq5cmTJigp556ypqzU6dOV12uZMmSmWr28fHJVHNERISSkpKsm+yEhIQ4fOaKFi2qggUL6uDBg2rYsKF+//13PfzwwwoMDFTFihXl4+Oj06dP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VK5cOT333HPq1q2bXn75ZXl4eOjDDz9Uz549Vbdu3auuX//+/TVnzhw1aNBAQ4YMUdGiRbVlyxYtXrxYO3bsyPK6wgYNGqhcuXLq3Lmzunfvrh07dljXB9+IO++8U35+fnrllVd03333qUKFCvrwww+Vnp6u8PBw5c+fX59//rnat29vHU2dOXOmqlSpYl3fDdyKOKIH3GYaNGigZcuW6cKFC1q7dq06duyo6dOnOzy36MqHdjuzjL+/vyIiIhyu5ZAuXZuUcS3aleM6s4x06aL+77//XvHx8VqzZo1KlSql3377LdOzra5WS6FChRQREeHwBfjKh+peb32//PKLunTponXr1qlgwYKKjo5WRESEdR3Zhx9+qBdffFGHDx/W77//roiICEVHR2f5xfB6anBzc9OCBQvUs2dPbdiwQX5+flq7dq1DDTnZjosWLVLRokW1fv16PfLII4qOjna4nuxa49zMmp3dRwsWLFBISIjmzZun1atXZ/tg+oceekgFChS45k1Yspu3ePHi2rx5s5566ilt375de/bsUZs2bfTrr7869Lvzzjs1a9YsnTx5Unv37tV///tfjRgxwnr/7bff1jvvvKOtW7dq3759ioyM1BtvvGE9+02SgoODtWXLFj3yyCPasGGDzp8/r7lz51rPKbvrrrvUokULq//LL7+sUaNGadKkSTp79qyGDh2qVatWqWDBglq5cqUKFCiguXPnOgScTz75RO+995527NihhIQELV68WH369Lnmf1J06NBBERERGjRokEN7q1atFBERoaFDh2a77H333ef00b4qVaro4Ycf1ueff261ubm56fnnn1ffvn2ta9sqVaqk3r17Z5rXmW1w5QPTP/vsM73zzjvatm2b4uPjtWDBAuXPn9/hWq4uXbpk+rlq2bKlKleubL3+6quv9MADD2jx4sWaP3++0/XkdJ/06NFDEyZM0Pnz57VixQrdfffd2rRpk/U8yldffVULFixQSkqK1q9fr9atWzt8Fj/44ANFRkZq37592r59uz744INMRx2zWl8PDw8tWLBAY8eO1aFDh7RhwwZVr15dW7ZsyfbUVA8PD61atUr33Xef1q1bp7Jly2rRokWKiIiwrusrWbKkIiIiHJYrWLCgIiIirH1w5e92f39/LV26VPny5dPcuXO1efNmTZs2Td27d9eePXu0detWDR06VD/88IOkS2etfPbZZ3rttdeyrBO4VbiZy0/4BwDctnbv3q0qVaooJibGevD37ebXX39Vp06dFBMTk+kapNwyevRozZw5M9OpmLg+hw4d0rvvvqsvvvjimncEzQ1nzpxxuNHKqlWr1LhxY+3fvz/Lh5vj1rNz50599dVXN+U6dCAvceomAOC2d+TIES1ZskTvvfeeBgwYkGchD7mvTJky+vLLL2/afBMnTtTmzZsVFham48eP6+OPP1a/fv0IeTZy1113EfJgCwQ9AICk7E9HvB0cO3ZMCxcu1GOPPebwzLC8cOUplbi1DB06VNOnT7euhfz666+t59IBwL8Jp24CAAAAgM1wMxYAAAAAsBmCHgAAAADYDEEPAAAAAGyGoAcAAAAANkPQAwAAAACbIegBAAAAgM0Q9AAAAADAZgh6AAAAAGAzBD0AAAAAsJn/A6MwxaoGhVwSAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "chain_a_scan = chain_a.unsqueeze(0).expand(len(requests), -1).clone()\n", "chain_b_scan = chain_b.unsqueeze(0).expand(len(requests), -1).clone()\n", "interface_scores = calculate_block_pair_ddg(\n", " packed_scan,\n", " chain_a_scan,\n", " chain_b_scan,\n", " sfxn=score_function,\n", " minimize=False,\n", " pack=False,\n", ")\n", "\n", "target_indices = torch.tensor(\n", " [block_index for block_index, _ in requests],\n", " dtype=torch.int64,\n", " device=device,\n", ")\n", "target_partner_by_term = calculate_block_pair_ddg(\n", " packed_scan,\n", " target_indices,\n", " chain_b_scan,\n", " sfxn=score_function,\n", " sum_terms=False,\n", " minimize=False,\n", " pack=False,\n", ")\n", "target_partner_scores = target_partner_by_term.sum(dim=0)\n", "\n", "whole_scorer = score_function.render_whole_pose_scoring_module(packed_scan)\n", "whole_scores = whole_scorer(packed_scan.coords)\n", "\n", "comparison_rows = []\n", "term_change_rows = []\n", "variant_poses = {}\n", "variant_notes = {}\n", "for site_index, target_block in enumerate(hotspot_blocks):\n", " wt_index = 2 * site_index\n", " mutant_index = wt_index + 1\n", " author_label = block_label(pose_stack, target_block)\n", " native_identity = pose_stack.block_type(0, target_block).name3\n", " comparison_rows.append(\n", " {\n", " \"site\": author_label,\n", " \"mutation\": f\"{native_identity}→ALA\",\n", " \"packing_shell_blocks\": int(packing_shells[wt_index].sum()),\n", " \"interface_score_change_non_ddg\": float(\n", " (interface_scores[mutant_index] - interface_scores[wt_index])\n", " .detach()\n", " .cpu()\n", " ),\n", " \"target_partner_score_change_non_ddg\": float(\n", " (target_partner_scores[mutant_index] - target_partner_scores[wt_index])\n", " .detach()\n", " .cpu()\n", " ),\n", " \"whole_pose_score_change_non_ddg\": float(\n", " (whole_scores[mutant_index] - whole_scores[wt_index]).detach().cpu()\n", " ),\n", " }\n", " )\n", " for term_index, score_type in enumerate(score_types):\n", " term_change_rows.append(\n", " {\n", " \"site\": author_label,\n", " \"term\": score_type.name,\n", " \"target_partner_score_change\": float(\n", " (\n", " target_partner_by_term[term_index, mutant_index]\n", " - target_partner_by_term[term_index, wt_index]\n", " )\n", " .detach()\n", " .cpu()\n", " ),\n", " }\n", " )\n", " for member_index, state in ((wt_index, \"repacked WT\"), (mutant_index, \"ALA\")):\n", " key = f\"{author_label} · {state}\"\n", " variant_poses[key] = packed_scan.split(member_index)\n", " variant_notes[key] = (\n", " f\"{native_identity}→{packed_scan.block_type(member_index, target_block).name3}; \"\n", " f\"same {int(packing_shells[member_index].sum())}-block packing shell\"\n", " )\n", "\n", "comparison_frame = pd.DataFrame(comparison_rows).sort_values(\n", " \"interface_score_change_non_ddg\", ascending=False\n", ")\n", "show_table(comparison_frame)\n", "\n", "plot_frame = comparison_frame.set_index(\"mutation\")[\n", " [\n", " \"interface_score_change_non_ddg\",\n", " \"target_partner_score_change_non_ddg\",\n", " \"whole_pose_score_change_non_ddg\",\n", " ]\n", "]\n", "ax = plot_frame.plot.barh(figsize=(9, 4.5))\n", "ax.axvline(0.0, color=\"black\", linewidth=0.8)\n", "ax.set(\n", " xlabel=\"alanine minus independently repacked WT (weighted score units)\",\n", " ylabel=\"\",\n", " title=\"Matched local-repacking comparisons\",\n", ")\n", "ax.legend(\n", " [\"chain A–B interface\", \"target–chain B\", \"whole pose\"],\n", " loc=\"best\",\n", ")\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 8, "id": "ec7cbe32", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", " \n", " \n", " \n", " \n", " \n", "\n", "
\n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
sitetermtarget_partner_score_change
24A:103fa_ljatr1.210048
26A:103fa_lk0.436216
25A:103fa_ljrep-0.111958
27A:103fa_elec0.055207
40A:103lk_ball_iso-0.000660
48A:115fa_ljatr1.358201
49A:115fa_ljrep-0.933421
50A:115fa_lk0.512924
65A:115lk_ball-0.197559
51A:115fa_elec0.147753
(5 more rows not shown)
\n", "\n", "\n" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " \n", "
\n", " \n", "
\n", "
TYR→TYR; same 41-block packing shell
\n", "
\n", "

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

\n", "
\n", "\n", "
\n", "
\n", "
TYR→ALA; same 41-block packing shell
\n", "
\n", "

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

\n", "
\n", "\n", "
\n", "
\n", "
PHE→PHE; same 41-block packing shell
\n", "
\n", "

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

\n", "
\n", "\n", "
\n", "
\n", "
PHE→ALA; same 41-block packing shell
\n", "
\n", "

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

\n", "
\n", "\n", "
\n", "
\n", "
VAL→VAL; same 24-block packing shell
\n", "
\n", "

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

\n", "
\n", "\n", "
\n", "
\n", "
VAL→ALA; same 24-block packing shell
\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": [ "term_change_frame = pd.DataFrame(term_change_rows)\n", "term_change_frame[\"absolute_change\"] = term_change_frame[\n", " \"target_partner_score_change\"\n", "].abs()\n", "dominant_term_changes = (\n", " term_change_frame.sort_values(\"absolute_change\", ascending=False)\n", " .groupby(\"site\", as_index=False, group_keys=False)\n", " .head(5)\n", " .sort_values([\"site\", \"absolute_change\"], ascending=[True, False])\n", ")\n", "show_table(dominant_term_changes.drop(columns=\"absolute_change\"))\n", "\n", "try:\n", " display(\n", " tmol.switchable_view(\n", " variant_poses,\n", " notes=variant_notes,\n", " width=760,\n", " height=440,\n", " )\n", " )\n", "except ImportError as exc:\n", " print(\"Interactive mutation comparison unavailable:\", exc)" ] }, { "cell_type": "markdown", "id": "e248ab57", "metadata": {}, "source": [ "**Expected observations.** The three alanine substitutions need not affect the\n", "full interface and their target-to-partner interactions by the same amount:\n", "local shell repacking redistributes interactions beyond the mutated side chain.\n", "A favorable native fixed-structure contribution does not guarantee a large\n", "post-repacking change. Large repulsive terms, extreme structural movement, or\n", "non-finite values should trigger inspection rather than automatic biological\n", "interpretation.\n", "\n", "The structure selector keeps each WT and alanine member side by side. It is a\n", "visual check on the actual packed structures, not just the score table. Because\n", "only one stochastic outcome is shown for each state, repeat the batch with\n", "several outcomes before discussing rank stability.\n", "\n", "## Rosetta and PyRosetta comparison\n", "\n", "Rosetta and PyRosetta provide mature alanine-scanning, interface analysis,\n", "residue selectors, TaskOperations, docking, and binding-energy protocol layers.\n", "This TMol example composes lower-level tensor APIs explicitly: author-label\n", "masks, block-pair score accounting, `PackerTask` restrictions, one batched\n", "packer call, and declared score reductions. It does not reproduce a Rosetta\n", "InterfaceAnalyzer or point-mutation protocol, and the numerical results are not\n", "cross-package parity claims.\n", "\n", "The scientific progression follows the Rosetta tutorials: inspect the input,\n", "state the score convention, choose movable residues, run one controlled change,\n", "analyze terms and structures, and document what the result cannot establish.\n", "\n", "## Exercises\n", "\n", "1. Scan five or ten chain-A sites and compare one large batch with chunked batches.\n", "2. Add several packing outcomes per WT/mutant state and plot their distributions.\n", "3. Replace the conservative enclosing-sphere shell with an explicitly documented atom-distance shell.\n", "4. Minimize identical local coordinate masks after packing and compare pre/post-minimization rankings.\n", "5. Repeat the analysis for A–D, another neighboring interface in the tetramer, and test symmetry consistency.\n", "\n", "## References\n", "\n", "- Doyle et al., [The structure of the potassium channel: molecular basis of K+ conduction and selectivity](https://pubmed.ncbi.nlm.nih.gov/9525859/)\n", "- [Rosetta scoring tutorial](https://docs.rosettacommons.org/demos/latest/tutorials/scoring/scoring)\n", "- [Rosetta packer tutorial](https://docs.rosettacommons.org/demos/latest/tutorials/Optimizing_Sidechains_The_Packer/Optimizing_Sidechains_The_Packer)\n", "- [Rosetta analysis tutorial](https://docs.rosettacommons.org/demos/latest/tutorials/analysis/Analysis)\n", "- [PyRosetta point-mutation scan](https://nbviewer.org/github/RosettaCommons/PyRosetta.notebooks/blob/master/notebooks/06.08-Point-Mutation-Scan.ipynb)\n", "- [PyRosetta distributed ddG/PSSM example](https://nbviewer.org/github/RosettaCommons/PyRosetta.notebooks/blob/master/notebooks/16.01-PyData-ddG-pssm.ipynb)" ] } ], "metadata": { "accelerator": "GPU", "colab": { "gpuType": "T4" }, "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }