{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Pose Operation\n",
    "\n",
    "@Author: 吴炜坤\n",
    "\n",
    "@email:weikun.wu@xtalpi.com weikunwu@163.com\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Pose中储存了非常多的信息,同时还提供了接口可以让用户方便的对其中的信息进行修改(采样)。\n",
    "本章节将着重介绍Pose的基本操作方式。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PyRosetta-4 2021 [Rosetta PyRosetta4.conda.mac.cxx11thread.serialization.python37.Release 2021.31+release.c7009b3115c22daa9efe2805d9d1ebba08426a54 2021-08-07T10:04:12] retrieved from: http://www.pyrosetta.org\n",
      "(C) Copyright Rosetta Commons Member Institutions. Created in JHU by Sergey Lyskov and PyRosetta Team.\n",
      "\u001b[0mcore.init: {0} \u001b[0mChecking for fconfig files in pwd and ./rosetta/flags\n",
      "\u001b[0mcore.init: {0} \u001b[0mRosetta version: PyRosetta4.conda.mac.cxx11thread.serialization.python37.Release r292 2021.31+release.c7009b3115c c7009b3115c22daa9efe2805d9d1ebba08426a54 http://www.pyrosetta.org 2021-08-07T10:04:12\n",
      "\u001b[0mcore.init: {0} \u001b[0mcommand: PyRosetta -ex1 -ex2aro -database /opt/miniconda3/lib/python3.7/site-packages/pyrosetta/database\n",
      "\u001b[0mbasic.random.init_random_generator: {0} \u001b[0m'RNG device' seed mode, using '/dev/urandom', seed=-1249606663 seed_offset=0 real_seed=-1249606663 thread_index=0\n",
      "\u001b[0mbasic.random.init_random_generator: {0} \u001b[0mRandomGenerator:init: Normal mode, seed=-1249606663 RG_type=mt19937\n",
      "\u001b[0mcore.chemical.GlobalResidueTypeSet: {0} \u001b[0mFinished initializing fa_standard residue type set.  Created 983 residue types\n",
      "\u001b[0mcore.chemical.GlobalResidueTypeSet: {0} \u001b[0mTotal time to initialize 0.695115 seconds.\n",
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/4R80.clean.pdb' automatically determined to be of type PDB\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0m\u001b[1m[ WARNING ]\u001b[0m missing heavyatom:  OXT on residue SER:CtermProteinFull 76\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0m\u001b[1m[ WARNING ]\u001b[0m missing heavyatom:  OXT on residue SER:CtermProteinFull 152\n"
     ]
    }
   ],
   "source": [
    "# 首先依然是从PDB中读入Pose\n",
    "from pyrosetta import init, pose_from_pdb\n",
    "init()\n",
    "pose = pose_from_pdb('./data/4R80.clean.pdb')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 一、 Pose的创建和复制\n",
    "前几节中提及过,pose是一个容器,理所当然我们可以创建一个空的容器,里面什么都不放。</br>\n",
    "很多时候,我们需要创建空的Pose对象,便于保存当前pose的实例化状态,可作为可回溯点或初始状态,方便反复调用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 通过创建一个新的Pose\n",
    "from pyrosetta import Pose\n",
    "copy_pose1 = Pose()\n",
    "copy_pose2 = None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "此处通过两种方法,将已有的Pose信息放入新的容器里,一种是通过assign函数复制,一种是通过python赋值符号来赋值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PDB file name: ./data/4R80.clean.pdb\n",
      "Total residues: 152\n",
      "Sequence: PSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGSPSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGS\n",
      "Fold tree:\n",
      "FOLD_TREE  EDGE 1 76 -1  EDGE 1 77 1  EDGE 77 152 -1 \n",
      "\n",
      "\n",
      "PDB file name: ./data/4R80.clean.pdb\n",
      "Total residues: 152\n",
      "Sequence: PSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGSPSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGS\n",
      "Fold tree:\n",
      "FOLD_TREE  EDGE 1 76 -1  EDGE 1 77 1  EDGE 77 152 -1 \n"
     ]
    }
   ],
   "source": [
    "# 方法1:通过assign复制新的构象\n",
    "copy_pose1.assign(pose)\n",
    "\n",
    "# 方法2:通过python的直接赋值符号\n",
    "copy_pose2 = pose\n",
    "\n",
    "print(copy_pose1)\n",
    "print('\\n')\n",
    "print(copy_pose2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可见,两种方式“看”起来里面都有了新的pose信息。但真的如此么?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "copy_pose1 24 residue phi:-91.24043946940483\n",
      "copy_pose2 24 residue phi:170.0\n"
     ]
    }
   ],
   "source": [
    "# 尝试调整初始pose中的24号氨基酸phi值:\n",
    "pose.set_phi(24, 170.0)\n",
    "\n",
    "# 查看对starting_pose以及starting_pose2的影响:\n",
    "print(f'copy_pose1 24 residue phi:{copy_pose1.phi(24)}')\n",
    "print(f'copy_pose2 24 residue phi:{copy_pose2.phi(24)}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "结果表明:\n",
    "- copy_pose2是用过python直接赋值的Pose并没有复制,而只是pose的一个\"超链接\"符,并没有进行\"复制\"的操作。\n",
    "- copy_pose1通过assign的复制,原始的pose的任何调整都没有对copy_pose1造成任何的影响,可见其独立性。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 二、 链与氨基酸操作\n",
    "先前章节中描述的都是对蛋白质的几何空间做参数的调整,而并不涉及到拓扑结构的改变。在PyRosetta中,对蛋白的结构域进行修改本质上就是对氨基酸的插入和删除。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.1 Pose中链的顺序交换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/6LZ9_H_L.pdb' automatically determined to be of type PDB\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 21 94\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYS\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYS\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 141 206\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 141 CYS\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 206 CYS\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 141 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 206 CYD\n",
      "PDB file name: ./data/6LZ9_H_L.pdb\n",
      " Pose Range  Chain    PDB Range  |   #Residues         #Atoms\n",
      "\n",
      "0001 -- 0081    H 0002  -- 0082  |   0081 residues;    01283 atoms\n",
      "0082 -- 0082    H 0082A -- 0082A |   0001 residues;    00011 atoms\n",
      "0083 -- 0083    H 0082B -- 0082B |   0001 residues;    00011 atoms\n",
      "0084 -- 0084    H 0082C -- 0082C |   0001 residues;    00019 atoms\n",
      "0085 -- 0102    H 0083  -- 0100  |   0018 residues;    00271 atoms\n",
      "0103 -- 0103    H 0100A -- 0100A |   0001 residues;    00010 atoms\n",
      "0104 -- 0104    H 0100B -- 0100B |   0001 residues;    00021 atoms\n",
      "0105 -- 0105    H 0100C -- 0100C |   0001 residues;    00021 atoms\n",
      "0106 -- 0106    H 0100D -- 0100D |   0001 residues;    00010 atoms\n",
      "0107 -- 0107    H 0100E -- 0100E |   0001 residues;    00017 atoms\n",
      "0108 -- 0119    H 0101  -- 0112  |   0012 residues;    00171 atoms\n",
      "0120 -- 0223    L 0002  -- 0105  |   0104 residues;    01588 atoms\n",
      "                           TOTAL |   0223 residues;    03433 atoms\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 链交换, 注意链号会变成AB.\n",
    "from pyrosetta.rosetta.protocols.simple_moves import SwitchChainOrderMover\n",
    "exchange_pose = pose_from_pdb('./data/6LZ9_H_L.pdb')\n",
    "print(exchange_pose.pdb_info())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.scoring.ScoreFunctionFactory: {0} \u001b[0mSCOREFUNCTION: \u001b[32mref2015\u001b[0m\n",
      "\u001b[0mcore.scoring.etable: {0} \u001b[0mStarting energy table calculation\n",
      "\u001b[0mcore.scoring.etable: {0} \u001b[0msmooth_etable: changing atr/rep split to bottom of energy well\n",
      "\u001b[0mcore.scoring.etable: {0} \u001b[0msmooth_etable: spline smoothing lj etables (maxdis = 6)\n",
      "\u001b[0mcore.scoring.etable: {0} \u001b[0msmooth_etable: spline smoothing solvation etables (max_dis = 6)\n",
      "\u001b[0mcore.scoring.etable: {0} \u001b[0mFinished calculating energy tables.\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/hbonds/ref2015_params/HBPoly1D.csv\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/hbonds/ref2015_params/HBFadeIntervals.csv\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/hbonds/ref2015_params/HBEval.csv\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/hbonds/ref2015_params/DonStrength.csv\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/hbonds/ref2015_params/AccStrength.csv\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/rama/fd/all.ramaProb\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/rama/fd/prepro.ramaProb\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/omega/omega_ppdep.all.txt\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/omega/omega_ppdep.gly.txt\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/omega/omega_ppdep.pro.txt\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/omega/omega_ppdep.valile.txt\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/P_AA_pp/P_AA\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/P_AA_pp/P_AA_n\n",
      "\u001b[0mcore.scoring.P_AA: {0} \u001b[0mshapovalov_lib::shap_p_aa_pp_smooth_level of 1( aka low_smooth ) got activated.\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/P_AA_pp/shapovalov/10deg/kappa131/a20.prop\n",
      "\u001b[0mprotocols.simple_moves.SwitchChainOrderMover: {0} \u001b[0mNumber of chains in pose: 2\n",
      "\u001b[0mprotocols.simple_moves.SwitchChainOrderMover: {0} \u001b[0mNow at chain: 2\n",
      "\u001b[0mprotocols.simple_moves.SwitchChainOrderMover: {0} \u001b[0mNow at chain: 1\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 22 87\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 22 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 87 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 22 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 87 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 125 198\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 125 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 198 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 125 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 198 CYD\n",
      "\u001b[0mbasic.io.database: {0} \u001b[0mDatabase file opened: scoring/score_functions/elec_cp_reps.dat\n",
      "\u001b[0mcore.scoring.elec.util: {0} \u001b[0mRead 40 countpair representative atoms\n",
      "\u001b[0mcore.pack.dunbrack.RotamerLibrary: {0} \u001b[0mshapovalov_lib_fixes_enable option is true.\n",
      "\u001b[0mcore.pack.dunbrack.RotamerLibrary: {0} \u001b[0mshapovalov_lib::shap_dun10_smooth_level of 1( aka lowest_smooth ) got activated.\n",
      "\u001b[0mcore.pack.dunbrack.RotamerLibrary: {0} \u001b[0mBinary rotamer library selected: /opt/miniconda3/lib/python3.7/site-packages/pyrosetta/database/rotamer/shapovalov/StpDwn_0-0-0/Dunbrack10.lib.bin\n",
      "\u001b[0mcore.pack.dunbrack.RotamerLibrary: {0} \u001b[0mUsing Dunbrack library binary file '/opt/miniconda3/lib/python3.7/site-packages/pyrosetta/database/rotamer/shapovalov/StpDwn_0-0-0/Dunbrack10.lib.bin'.\n",
      "\u001b[0mcore.pack.dunbrack.RotamerLibrary: {0} \u001b[0mDunbrack 2010 library took 0.181558 seconds to load from binary\n",
      "\u001b[0mprotocols.simple_moves.SwitchChainOrderMover: {0} \u001b[0mNew pose's foldtree FOLD_TREE  EDGE 1 104 -1  EDGE 1 105 1  EDGE 105 223 -1\n",
      "PDB file name: \n",
      " Pose Range  Chain    PDB Range  |   #Residues         #Atoms\n",
      "\n",
      "0001 -- 0104    A 0001  -- 0104  |   0104 residues;    01588 atoms\n",
      "0105 -- 0223    B 0105  -- 0223  |   0119 residues;    01845 atoms\n",
      "                           TOTAL |   0223 residues;    03433 atoms\n",
      "\n"
     ]
    }
   ],
   "source": [
    "switch_chains = SwitchChainOrderMover()\n",
    "switch_chains.chain_order(\"LH\")\n",
    "switch_chains.apply(exchange_pose)\n",
    "print(exchange_pose.pdb_info())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注意,这种方法虽然可以进行链交换,但是其中的PDB_info被强制更新为A链和B链了,如果需要保留原有的PDB信息系统,就不应该用这种快捷修改的方式!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.2 Pose中链的删除\n",
    "Pose中的链是可以被整条删除的。(反之也可以添加)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mprotocols.simple_moves.DeleteChainMover: {0} \u001b[0mRemoving chain 1 from pose with 2 chains\n",
      "PDB file name: ./data/4R80.clean.pdb\n",
      " Pose Range  Chain    PDB Range  |   #Residues         #Atoms\n",
      "\n",
      "0001 -- 0076    B 0001  -- 0076  |   0076 residues;    01251 atoms\n",
      "                           TOTAL |   0076 residues;    01251 atoms\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 链删除\n",
    "from pyrosetta.rosetta.protocols.simple_moves import DeleteChainMover\n",
    "delete_chain = DeleteChainMover()\n",
    "delete_chain.chain_num(1)\n",
    "delete_chain.apply(pose)\n",
    "print(pose.pdb_info())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可见A链已经在Pose中消失,而B链还存在。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.3 Pose中链的索引分离\n",
    "尽管pose的氨基酸编号是忽略多肽链的分隔的,pose中的链依然是根据多肽链的物理结构进行编号的,同理也是从1开始编号。\n",
    "如一个蛋白中有2条链A和B,那么链编号结果即为1和2。其中A对应1号链,B对应2号链,与PDB的链顺序有关(当然A链的顺序如果在后面,那么B链就是1号链)。\n",
    "Pose类中许多的方法可以很方便对链的增减进行操作, 以下2个举例进行说明:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/6LZ9_H_L.pdb' automatically determined to be of type PDB\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 21 94\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYS\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYS\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 141 206\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 141 CYS\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 206 CYS\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 141 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 206 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 21 94\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 22 87\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 22 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 87 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 22 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 87 CYD\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "vector1_std_shared_ptr_core_pose_Pose_t[0x7ff14f8106a8, 0x7ff14e6a6a18]"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 将Pose按照链的数量进行切割\n",
    "pose = pose_from_pdb('./data/6LZ9_H_L.pdb')\n",
    "pose_list = pose.split_by_chain()\n",
    "pose_list"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "此处的pose_list中存放了2个数据,说明链已经被切割成2个独立的pose对象了。\n",
    "\n",
    "通过python的索引,可以获得具体的pose:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 21 94\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 22 87\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 22 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 87 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 22 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 87 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 21 94\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 22 87\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 22 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 87 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 22 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 87 CYD\n",
      "PDB file name: ./data/6LZ9_H_L.pdb\n",
      " Pose Range  Chain    PDB Range  |   #Residues         #Atoms\n",
      "\n",
      "0001 -- 0081    H 0002  -- 0082  |   0081 residues;    01283 atoms\n",
      "0082 -- 0082    H 0082A -- 0082A |   0001 residues;    00011 atoms\n",
      "0083 -- 0083    H 0082B -- 0082B |   0001 residues;    00011 atoms\n",
      "0084 -- 0084    H 0082C -- 0082C |   0001 residues;    00019 atoms\n",
      "0085 -- 0102    H 0083  -- 0100  |   0018 residues;    00271 atoms\n",
      "0103 -- 0103    H 0100A -- 0100A |   0001 residues;    00010 atoms\n",
      "0104 -- 0104    H 0100B -- 0100B |   0001 residues;    00021 atoms\n",
      "0105 -- 0105    H 0100C -- 0100C |   0001 residues;    00021 atoms\n",
      "0106 -- 0106    H 0100D -- 0100D |   0001 residues;    00010 atoms\n",
      "0107 -- 0107    H 0100E -- 0100E |   0001 residues;    00017 atoms\n",
      "0108 -- 0119    H 0101  -- 0112  |   0012 residues;    00171 atoms\n",
      "                           TOTAL |   0119 residues;    01845 atoms\n",
      "\n",
      "PDB file name: ./data/6LZ9_H_L.pdb\n",
      " Pose Range  Chain    PDB Range  |   #Residues         #Atoms\n",
      "\n",
      "0001 -- 0104    L 0002  -- 0105  |   0104 residues;    01588 atoms\n",
      "                           TOTAL |   0104 residues;    01588 atoms\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 获取只含有第一个链的pose\n",
    "chain1_pose = pose.split_by_chain()[1]  # 直接切片索引链号。\n",
    "chain2_pose = pose.split_by_chain()[2]  # 直接切片索引链号。\n",
    "\n",
    "# check\n",
    "print(chain1_pose.pdb_info())\n",
    "print(chain2_pose.pdb_info())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.4 Pose链的合并或延伸\n",
    "除了索引操作,用户还可以通过一些简单的方式把链合并到一个pose中,此处使用append_pose_to_pose函数就可以达到目的。但需要注意,pose中的氨基酸、链的数量变化后,都需要对PDBinfo进行更新。否则PDBinfo的信息与Pose信息不对称。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**添加新的链**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 21 94\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 141 206\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 141 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 206 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 141 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 206 CYD\n"
     ]
    }
   ],
   "source": [
    "# 将chain2加载到chain1 pose的最后一个氨基酸的后面。\n",
    "chain1_pose_last_residue = chain1_pose.total_residue()\n",
    "chain1_pose.append_pose_by_jump(chain2_pose, jump_anchor_residue=chain1_pose_last_residue)\n",
    "chain1_pose.update_residue_neighbors()\n",
    "chain1_pose.update_pose_chains_from_pdb_chains()\n",
    "chain1_pose.conformation().detect_disulfides()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PDB file name: ./data/6LZ9_H_L.pdb\n",
      " Pose Range  Chain    PDB Range  |   #Residues         #Atoms\n",
      "\n",
      "0001 -- 0081    H 0002  -- 0082  |   0081 residues;    01283 atoms\n",
      "0082 -- 0082    H 0082A -- 0082A |   0001 residues;    00011 atoms\n",
      "0083 -- 0083    H 0082B -- 0082B |   0001 residues;    00011 atoms\n",
      "0084 -- 0084    H 0082C -- 0082C |   0001 residues;    00019 atoms\n",
      "0085 -- 0102    H 0083  -- 0100  |   0018 residues;    00271 atoms\n",
      "0103 -- 0103    H 0100A -- 0100A |   0001 residues;    00010 atoms\n",
      "0104 -- 0104    H 0100B -- 0100B |   0001 residues;    00021 atoms\n",
      "0105 -- 0105    H 0100C -- 0100C |   0001 residues;    00021 atoms\n",
      "0106 -- 0106    H 0100D -- 0100D |   0001 residues;    00010 atoms\n",
      "0107 -- 0107    H 0100E -- 0100E |   0001 residues;    00017 atoms\n",
      "0108 -- 0119    H 0101  -- 0112  |   0012 residues;    00171 atoms\n",
      "0120 -- 0223    L 0002  -- 0105  |   0104 residues;    01588 atoms\n",
      "                           TOTAL |   0223 residues;    03433 atoms\n",
      "\n",
      "PDBinfo是否需要被更新:True\n"
     ]
    }
   ],
   "source": [
    "print(chain1_pose.pdb_info())\n",
    "\n",
    "# 检查Pose的PDB_info是否是奇怪的:\n",
    "print(f'PDBinfo是否需要被更新:{chain1_pose.pdb_info().obsolete()}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PDBinfo是否需要被更新:False\n"
     ]
    }
   ],
   "source": [
    "# update pdbinfo; 别忘了更新pdbinfo;\n",
    "from pyrosetta.rosetta.core.pose import renumber_pdbinfo_based_on_conf_chains\n",
    "renumber_pdbinfo_based_on_conf_chains(chain1_pose)\n",
    "print(f'PDBinfo是否需要被更新:{chain1_pose.pdb_info().obsolete()}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 如果你非常确定,新的pose中不会有PDB的编号冲突等问题。可以直接修改obsolete的检查结果:\n",
    "chain1_pose.pdb_info().obsolete(False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**合并为一条多肽链的case**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/6LZ9_H_L.pdb' automatically determined to be of type PDB\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 21 94\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYS\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYS\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 141 206\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 141 CYS\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 206 CYS\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 141 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 206 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 21 94\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 22 87\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 22 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 87 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 22 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 87 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 21 94\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 21 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 94 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mFound disulfide between residues 22 87\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 22 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 87 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 22 CYD\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0mcurrent variant for 87 CYD\n",
      "append之后的chain1_pose中的氨基酸总数:223\n",
      "append之后chain的总数:1\n",
      "PDB file name: ./data/6LZ9_H_L.pdb\n",
      " Pose Range  Chain    PDB Range  |   #Residues         #Atoms\n",
      "\n",
      "0001 -- 0223    H 0002  -- 0224  |   0223 residues;    03433 atoms\n",
      "                           TOTAL |   0223 residues;    03433 atoms\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 链的延伸; 合并成一条链的意思;\n",
    "from pyrosetta.rosetta.core.pose import append_pose_to_pose\n",
    "pose = pose_from_pdb('./data/6LZ9_H_L.pdb')\n",
    "chain1_pose = pose.split_by_chain()[1]\n",
    "chain2_pose = pose.split_by_chain()[2]\n",
    "\n",
    "new_chain = False\n",
    "combine_pose = Pose()\n",
    "combine_pose.assign(chain1_pose)\n",
    "append_pose_to_pose(combine_pose, chain2_pose, new_chain)\n",
    "\n",
    "# update pdbinfo; 别忘了更新pdbinfo;\n",
    "renumber_pdbinfo_based_on_conf_chains(combine_pose)\n",
    "\n",
    "print(f'append之后的chain1_pose中的氨基酸总数:{combine_pose.total_residue()}')\n",
    "combine_pose.sequence()\n",
    "print(f'append之后chain的总数:{combine_pose.num_chains()}')\n",
    "print(combine_pose.pdb_info())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.5 Pose中删除Region区域\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/4R80.clean.pdb' automatically determined to be of type PDB\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0m\u001b[1m[ WARNING ]\u001b[0m missing heavyatom:  OXT on residue SER:CtermProteinFull 76\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0m\u001b[1m[ WARNING ]\u001b[0m missing heavyatom:  OXT on residue SER:CtermProteinFull 152\n",
      "删除前的PDB_info:\n",
      "PDB file name: ./data/4R80.clean.pdb\n",
      " Pose Range  Chain    PDB Range  |   #Residues         #Atoms\n",
      "\n",
      "0001 -- 0076    A 0001  -- 0076  |   0076 residues;    01251 atoms\n",
      "0077 -- 0152    B 0001  -- 0076  |   0076 residues;    01251 atoms\n",
      "                           TOTAL |   0152 residues;    02502 atoms\n",
      "\n",
      "\u001b[0mprotocols.grafting.util: {0} \u001b[0mDeleting 50 residues from 1 to 50\n",
      "删除后的PDB_info:\n",
      "PDB file name: ./data/4R80.clean.pdb\n",
      " Pose Range  Chain    PDB Range  |   #Residues         #Atoms\n",
      "\n",
      "0001 -- 0026    A 0051  -- 0076  |   0026 residues;    00412 atoms\n",
      "0027 -- 0102    B 0001  -- 0076  |   0076 residues;    01251 atoms\n",
      "                           TOTAL |   0102 residues;    01663 atoms\n",
      "\n"
     ]
    }
   ],
   "source": [
    "pose = pose_from_pdb('./data/4R80.clean.pdb')\n",
    "print('删除前的PDB_info:')\n",
    "print(pose.pdb_info())\n",
    "from pyrosetta.rosetta.protocols.grafting import delete_region\n",
    "delete_region_mover = delete_region(pose, 1, 50)  # 此处是pose number;\n",
    "\n",
    "# update pdbinfo; 别忘了更新pdbinfo;\n",
    "renumber_pdbinfo_based_on_conf_chains(pose)\n",
    "\n",
    "# 打印查看信息, 一整个区域都被删除【比一个个氨基酸删除快得多】:\n",
    "print('删除后的PDB_info:')\n",
    "print(pose.pdb_info())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从pdb_info中可见,A链的1-50号氨基酸消失了。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.6 Pose中单独氨基酸的删减操作"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "除了对链的合并之外,我们还可以对链中的氨基酸进行添加、删除的操作!具体的过程是用户需要创建一个独立的氨基酸(residue object),并将这个氨基酸加载到现有的构像中。\n",
    "加载的方式可以是前置或后置,根据使用的函数不同而定。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/4R80.clean.pdb' automatically determined to be of type PDB\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0m\u001b[1m[ WARNING ]\u001b[0m missing heavyatom:  OXT on residue SER:CtermProteinFull 76\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0m\u001b[1m[ WARNING ]\u001b[0m missing heavyatom:  OXT on residue SER:CtermProteinFull 152\n",
      "原始氨基酸总数:152\n",
      "原始氨基酸序列:PSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGSPSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGS\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 获取初始信息\n",
    "from pyrosetta.rosetta.core.conformation import ResidueFactory\n",
    "from pyrosetta.rosetta.core.chemical import ChemicalManager\n",
    "\n",
    "# print\n",
    "pose = pose_from_pdb('./data/4R80.clean.pdb')\n",
    "print(f'原始氨基酸总数:{pose.total_residue()}')\n",
    "print(f'原始氨基酸序列:{pose.sequence()}\\n')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Pose的残基数量:153\n",
      "氨基酸序列:APSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGSPSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGS\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 通过ResidueFactory创建一个新的Residue(ALA)对象:\n",
    "chm = ChemicalManager.get_instance()\n",
    "rts = chm.residue_type_set(\"fa_standard\")\n",
    "new_rsd = ResidueFactory.create_residue(rts.name_map('ALA')) # 创建一个residue object\n",
    "\n",
    "# 在第一个氨基酸前添加一个ALA\n",
    "pose.prepend_polymer_residue_before_seqpos(new_rsd, 1, True) \n",
    "\n",
    "print(f'Pose的残基数量:{pose.total_residue()}')\n",
    "print(f'氨基酸序列:{pose.sequence()}\\n')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Pose的残基数量:154\n",
      "氨基酸序列:APSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGSPSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGSA\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 向后添加氨基酸\n",
    "last_residue = pose.total_residue()\n",
    "pose.append_polymer_residue_after_seqpos(new_rsd, last_residue, True)  # 在最后一个氨基酸后添加一个ALA\n",
    "\n",
    "print(f'Pose的残基数量:{pose.total_residue()}')\n",
    "print(f'氨基酸序列:{pose.sequence()}\\n')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "删除之后氨基酸总数:153\n",
      "删除之后氨基酸序列:PSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGSPSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGSA\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 删除氨基酸\n",
    "pose.delete_polymer_residue(1)  # 删除第一个氨基酸\n",
    "\n",
    "print(f'删除之后氨基酸总数:{pose.total_residue()}')\n",
    "print(f'删除之后氨基酸序列:{pose.sequence()}\\n')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "删除之后氨基酸总数:148\n",
      "删除之后氨基酸序列:EKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGSPSEEEEKRRAKQVAKEKILEQNPSSKVQVRRVQKQGNTIRVELEITENGKKTNITVEVEKQGNTFTVKRITETVGSA\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 还可以范围性的删除氨基酸\n",
    "pose.delete_residue_range_slow(1,5) # 删除第一个至第五个氨基酸\n",
    "\n",
    "print(f'删除之后氨基酸总数:{pose.total_residue()}')\n",
    "print(f'删除之后氨基酸序列:{pose.sequence()}\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**对拓扑结构操作完后,千万记得PBDinfo更新!!**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PDBinfo是否需要被更新:False\n",
      "PDB file name: ./data/4R80.clean.pdb\n",
      " Pose Range  Chain    PDB Range  |   #Residues         #Atoms\n",
      "\n",
      "0001 -- 0071    A 0006  -- 0076  |   0071 residues;    01177 atoms\n",
      "0072 -- 0148    B 0001  -- 0077  |   0077 residues;    01260 atoms\n",
      "                           TOTAL |   0148 residues;    02437 atoms\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 更新pdb_info; [别忘了!]\n",
    "from pyrosetta.rosetta.core.pose import renumber_pdbinfo_based_on_conf_chains\n",
    "\n",
    "renumber_pdbinfo_based_on_conf_chains(pose)  # 更新PDBinfo.\n",
    "\n",
    "# 检查PDBinfo是否正确: Returns true if PDBInfo is obsolete and needs updating\n",
    "print(f'PDBinfo是否需要被更新:{pose.pdb_info().obsolete()}')\n",
    "print(pose.pdb_info())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.7 Pose中连续region提取\n",
    "在之前的章节里面我们提过,Pose中的每个氨基酸都是独立的构象,我们可以使用这个机制将Pose中一些连续的片段进行提取。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/4R80.clean.pdb' automatically determined to be of type PDB\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0m\u001b[1m[ WARNING ]\u001b[0m missing heavyatom:  OXT on residue SER:CtermProteinFull 76\n",
      "\u001b[0mcore.conformation.Conformation: {0} \u001b[0m\u001b[1m[ WARNING ]\u001b[0m missing heavyatom:  OXT on residue SER:CtermProteinFull 152\n",
      "PDB file name: ./data/4R80.clean.pdb\n",
      " Pose Range  Chain    PDB Range  |   #Residues         #Atoms\n",
      "\n",
      "0001 -- 0076    A 0001  -- 0076  |   0076 residues;    01251 atoms\n",
      "0077 -- 0152    B 0001  -- 0076  |   0076 residues;    01251 atoms\n",
      "                           TOTAL |   0152 residues;    02502 atoms\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 读取pose\n",
    "pose = pose_from_pdb('./data/4R80.clean.pdb')\n",
    "print(pose.pdb_info())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "P\n"
     ]
    }
   ],
   "source": [
    "# 新建一个空的Pose\n",
    "sub_region_pose = Pose()\n",
    "\n",
    "# 添加第一个氨基酸:\n",
    "residue = pose.residue(1)\n",
    "sub_region_pose.append_residue_by_jump(new_rsd=residue, jump_anchor_residue=1)\n",
    "print(sub_region_pose.sequence())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PSEEE\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 添加第2-5个氨基酸:\n",
    "for i in range(2, 6):\n",
    "    residue = pose.residue(i)  # 索引原pose中的residue\n",
    "    last_residue_pose_id = sub_region_pose.total_residue()  # 获取sub_region_pose中的最后一个氨基酸;\n",
    "    sub_region_pose.append_polymer_residue_after_seqpos(new_rsd=residue, seqpos=last_residue_pose_id, build_ideal_geometry=False)  # 将氨基酸添加\n",
    "print(sub_region_pose.sequence())\n",
    "sub_region_pose.dump_pdb('./data/sub_region.pdb')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n"
     ]
    }
   ],
   "source": [
    "# 这种非官方的操作方法,默认没有创建pdb_info!\n",
    "print(sub_region_pose.pdb_info())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PDB file name: \n",
      " Pose Range  Chain    PDB Range  |   #Residues         #Atoms\n",
      "\n",
      "0001 -- 0005    A 0001  -- 0005  |   0005 residues;    00074 atoms\n",
      "                           TOTAL |   0005 residues;    00074 atoms\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 通过AddPDBInfoMover可以创建对应的pdb_info给到当前的Pose\n",
    "from pyrosetta.rosetta.protocols.simple_moves import AddPDBInfoMover\n",
    "pdb_mover = AddPDBInfoMover()\n",
    "pdb_mover.apply(sub_region_pose)\n",
    "print(sub_region_pose.pdb_info())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.8 Pose中氨基酸类型的调整(突变)\n",
    "除了具体的化学键数据的调整,在PyRosetta中进行氨基酸的类型调整也是很方便的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "原始氨基酸类型:PRO:NtermProteinFull\n"
     ]
    }
   ],
   "source": [
    "# 调整氨基酸的类型\n",
    "from pyrosetta.toolbox import mutate_residue\n",
    "print(f'原始氨基酸类型:{pose.residue(1).name()}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "突变氨基酸中...\n",
      "\u001b[0mcore.scoring.ScoreFunctionFactory: {0} \u001b[0mSCOREFUNCTION: \u001b[32mref2015\u001b[0m\n",
      "\u001b[0mcore.pack.task: {0} \u001b[0mPacker task: initialize from command line()\n",
      "\u001b[0mcore.pack.pack_rotamers: {0} \u001b[0mbuilt 161 rotamers at 8 positions.\n",
      "\u001b[0mcore.pack.pack_rotamers: {0} \u001b[0mRequesting all available threads for interaction graph computation.\n",
      "\u001b[0mcore.pack.interaction_graph.interaction_graph_factory: {0} \u001b[0mInstantiating PDInteractionGraph\n",
      "\u001b[0mbasic.thread_manager.RosettaThreadManager: {?} \u001b[0mCreating a thread pool of 1 threads.\n",
      "\u001b[0mbasic.thread_manager.RosettaThreadPool: {?} \u001b[0mLaunched 0 new threads.\n",
      "\u001b[0mcore.pack.rotamer_set.RotamerSets: {0} \u001b[0mCompleted interaction graph pre-calculation in 1 available threads (1 had been requested).\n"
     ]
    }
   ],
   "source": [
    "print('突变氨基酸中...')\n",
    "mutate_residue(pose, 1, 'C', 9.0)  # 1 代表氨基酸突变的pose编号,9.0代表对氨基酸附近9埃范围内的氨基酸进行侧链优化,适应新的突变。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "突变后氨基酸类型:CYS:NtermProteinFull\n"
     ]
    }
   ],
   "source": [
    "print(f'突变后氨基酸类型:{pose.residue(1).name()}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 三、Pose中的自定义信息储存\n",
    "Pose中含有让用户自定义写入任何信息的功能,比如在程序设计过程中,中间生成的临时数值或字符都可以写入到PoseExtraScore中,这些信息会随着Pose一并输出到PDB或则Silent文件中,在后续的分析和处理的过程中非常方便。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 给pose加入额外的信息: 比如filter计算的值就可以储存.\n",
    "from pyrosetta.rosetta.core.pose import setPoseExtraScore, getPoseExtraScore\n",
    "\n",
    "setPoseExtraScore(pose, \"distance\", 1.0)\n",
    "setPoseExtraScore(pose, \"angle\", 120.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.0\n",
      "120.5\n"
     ]
    }
   ],
   "source": [
    "# 提取信息\n",
    "print(getPoseExtraScore(pose, 'distance'))\n",
    "print(getPoseExtraScore(pose, 'angle'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 练习\n",
    "1. 尝试写一个程序,将Pose(单链)中某一个连续的结构域部分提取出来。\n",
    "2. 尝试写一个程序,将Pose(单链)中某两个不同的连续结构域提取出来,并重新分为两条链。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "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.7.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}