{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7436dcbe-e3eb-46e8-8e8b-6ce6dc70f318",
   "metadata": {},
   "source": [
    "# Rosetta Constraint API\n",
    "\n",
    "@Author: 吴炜坤\n",
    "\n",
    "@email: weikun.wu@xtalpi.com"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4b0da714-2a7c-462e-8bbd-4b35bd55c488",
   "metadata": {},
   "source": [
    "在前面的章节中,我们介绍了在Rosetta中如何定义需要的约束文件。这些文件的定义和约束都是手动的。 在本章节中,我们将会介绍:\n",
    "\n",
    "如何从file读取constraint至pose中\n",
    "如何使用constraint生成器自动生成约束\n",
    "如何管理Pose中的约束"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5e9f0ee-92cf-4382-92e2-b22a8878560e",
   "metadata": {},
   "source": [
    "### 一、从几何约束文件读取约束"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5906585-13d6-48bc-bce8-201c2d78afc1",
   "metadata": {},
   "source": [
    "这里我们将使用ROSETTA中的constraint file(限制文件)。\n",
    "举例,我们当前对20号和6号Ca原子进行距离的约束,目标约束距离为9埃。\n",
    "\n",
    "constraint file的内容如下:\n",
    "```\n",
    "AtomPair CA 20 CA 6 LINEAR_PENALTY 9.0 0 0 1.0\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c04c5515-cb29-4519-9abf-a31fe89df454",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PyRosetta-4 2021 [Rosetta PyRosetta4.conda.mac.cxx11thread.serialization.python37.Release 2021.26+release.b308454c455dd04f6824cc8b23e54bbb9be2cdd7 2021-07-02T13:01:54] 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 r288 2021.26+release.b308454c455 b308454c455dd04f6824cc8b23e54bbb9be2cdd7 http://www.pyrosetta.org 2021-07-02T13:01:54\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=-1705239655 seed_offset=0 real_seed=-1705239655 thread_index=0\n",
      "\u001b[0mbasic.random.init_random_generator: {0} \u001b[0mRandomGenerator:init: Normal mode, seed=-1705239655 RG_type=mt19937\n"
     ]
    }
   ],
   "source": [
    "# 在1ubq_clean.pdb的例子上施加原子对的限制\n",
    "\n",
    "from pyrosetta import init, create_score_function, pose_from_pdb\n",
    "from pyrosetta.rosetta.core.scoring import ScoreType\n",
    "init()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "6fabe42d-e6b0-4e4c-ba9c-549301bbcfdf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\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[0mcore.chemical.GlobalResidueTypeSet: {0} \u001b[0mFinished initializing fa_standard residue type set.  Created 984 residue types\n",
      "\u001b[0mcore.chemical.GlobalResidueTypeSet: {0} \u001b[0mTotal time to initialize 0.684347 seconds.\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"
     ]
    }
   ],
   "source": [
    "# 初始化REF2015的打分函数对象:\n",
    "scorefxn = create_score_function('ref2015')\n",
    "\n",
    "# 激活相关惩罚项的打分函数权重:\n",
    "scorefxn.set_weight(ScoreType.atom_pair_constraint, 1.0) "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30561306-1738-489b-a39e-367fbec6af92",
   "metadata": {},
   "source": [
    "从文件读取约束信息主要依靠ConstraintSetMover的作用:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "5235c20a-f8e0-4ff7-a2af-f73b0e06b479",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyrosetta.rosetta.protocols.constraint_movers import ConstraintSetMover\n",
    "cst_set = ConstraintSetMover()\n",
    "cst_set.add_constraints(False) # True=在原有限制基础上额外再添加限制,False= 从文件中读取并覆盖所有的限制。\n",
    "cst_set.constraint_file('./data/constraint_file')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "01325811-8b2d-4793-abe6-e119bbfe69bb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/1ubq_clean.pdb' automatically determined to be of type PDB\n",
      "\u001b[0mcore.scoring.constraints.ConstraintsIO: {0} \u001b[0mread constraints from ./data/constraint_file\n",
      "\u001b[0mcore.scoring.constraints.ConstraintsIO: {0} \u001b[0mRead in 1 constraints\n"
     ]
    }
   ],
   "source": [
    "# load pose from 1ubq_clean.pdb\n",
    "pose = pose_from_pdb(\"./data/1ubq_clean.pdb\")\n",
    "cst_set.apply(pose)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "521ef55a-c19a-4a17-80c2-eb3fe3faef8e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ResiduePairConstraints: total: 20   plotting active...\n",
      "ResiduePairConstraints (6,20)\n",
      "AtomPairConstraint (2,20-2,6)\n",
      "         r      func     dfunc dfunc_est\n",
      "         2     7.000    -1.000    -1.000\n",
      "       2.5     6.500    -1.000    -1.000\n",
      "         3     6.000    -1.000    -1.000\n",
      "       3.5     5.500    -1.000    -1.000\n",
      "         4     5.000    -1.000    -1.000\n",
      "       4.5     4.500    -1.000    -1.000\n",
      "         5     4.000    -1.000    -1.000\n",
      "       5.5     3.500    -1.000    -1.000\n",
      "         6     3.000    -1.000    -1.000\n",
      "       6.5     2.500    -1.000    -1.000\n",
      "         7     2.000    -1.000    -1.000\n",
      "       7.5     1.500    -1.000    -1.000\n",
      "         8     1.000    -1.000    -1.000\n",
      "       8.5     0.500    -1.000    -1.000\n",
      "         9     0.000     0.000     0.000\n",
      "       9.5     0.500     1.000     1.000\n",
      "        10     1.000     1.000     1.000\n",
      "      10.5     1.500     1.000     1.000\n",
      "        11     2.000     1.000     1.000\n",
      "      11.5     2.500     1.000     1.000\n",
      "        12     3.000     1.000     1.000\n",
      "      12.5     3.500     1.000     1.000\n",
      "        13     4.000     1.000     1.000\n",
      "      13.5     4.500     1.000     1.000\n",
      "        14     5.000     1.000     1.000\n",
      "      14.5     5.500     1.000     1.000\n",
      "        15     6.000     1.000     1.000\n",
      "      15.5     6.500     1.000     1.000\n",
      "        16     7.000     1.000     1.000\n",
      "      16.5     7.500     1.000     1.000\n",
      "        17     8.000     1.000     1.000\n",
      "      17.5     8.500     1.000     1.000\n",
      "        18     9.000     1.000     1.000\n",
      "      18.5     9.500     1.000     1.000\n",
      "        19    10.000     1.000     1.000\n",
      "      19.5    10.500     1.000     1.000\n",
      "        20    11.000     1.000     1.000\n",
      "\n",
      "ResiduePairConstraints (20,6)\n",
      "AtomPairConstraint (2,20-2,6)\n",
      "         r      func     dfunc dfunc_est\n",
      "         2     7.000    -1.000    -1.000\n",
      "       2.5     6.500    -1.000    -1.000\n",
      "         3     6.000    -1.000    -1.000\n",
      "       3.5     5.500    -1.000    -1.000\n",
      "         4     5.000    -1.000    -1.000\n",
      "       4.5     4.500    -1.000    -1.000\n",
      "         5     4.000    -1.000    -1.000\n",
      "       5.5     3.500    -1.000    -1.000\n",
      "         6     3.000    -1.000    -1.000\n",
      "       6.5     2.500    -1.000    -1.000\n",
      "         7     2.000    -1.000    -1.000\n",
      "       7.5     1.500    -1.000    -1.000\n",
      "         8     1.000    -1.000    -1.000\n",
      "       8.5     0.500    -1.000    -1.000\n",
      "         9     0.000     0.000     0.000\n",
      "       9.5     0.500     1.000     1.000\n",
      "        10     1.000     1.000     1.000\n",
      "      10.5     1.500     1.000     1.000\n",
      "        11     2.000     1.000     1.000\n",
      "      11.5     2.500     1.000     1.000\n",
      "        12     3.000     1.000     1.000\n",
      "      12.5     3.500     1.000     1.000\n",
      "        13     4.000     1.000     1.000\n",
      "      13.5     4.500     1.000     1.000\n",
      "        14     5.000     1.000     1.000\n",
      "      14.5     5.500     1.000     1.000\n",
      "        15     6.000     1.000     1.000\n",
      "      15.5     6.500     1.000     1.000\n",
      "        16     7.000     1.000     1.000\n",
      "      16.5     7.500     1.000     1.000\n",
      "        17     8.000     1.000     1.000\n",
      "      17.5     8.500     1.000     1.000\n",
      "        18     9.000     1.000     1.000\n",
      "      18.5     9.500     1.000     1.000\n",
      "        19    10.000     1.000     1.000\n",
      "      19.5    10.500     1.000     1.000\n",
      "        20    11.000     1.000     1.000\n",
      "\n",
      "IntraResidueConstraints: total: 0 showing active...\n",
      "NonResiduePairConstraints: total: 0 showing active...\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 打印查看当前pose所有设定的constraint\n",
    "print(pose.constraint_set())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "49f19e63-b563-42a5-b2b6-5bf413760538",
   "metadata": {},
   "source": [
    "从这个简单的例子中可以看到,使用“限制文件”对pose进行限制的方法理论上适用于所有的场景。因为只要我们按照Rosetta的要求编写所有的限制规则于限制文件中,这种方法就可以最大化用户自由度,但是缺点是使用“限制文件”事先需要对限制文件的编写规则有一定的了解和把握。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d1999ab-d03b-4abc-9507-fddaad7515b6",
   "metadata": {},
   "source": [
    "### 二、从序列约束文件读取约束\n",
    "\n",
    "主要通过AddCompositionConstraintMover,AddNetChargeConstraintMover两个函数来进行约束的添加。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02c6aac0-8060-4112-9d53-c640a04d93c4",
   "metadata": {},
   "source": [
    "#### 2.1 AddCompositionConstraintMover\n",
    "给氨基酸的组成比例添加限制。开始使用前,需要准备*.comp限制文件,控制如何限制氨基酸的比例。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "47cb2b8e-ed45-4a2b-ae08-48065f052465",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mprotocols.aa_composition.AddCompositionConstraintMover: {0} \u001b[0mInitialized AACompositionConstraint object from file ./data/aa_comp_constraint_file.comp.\n"
     ]
    }
   ],
   "source": [
    "from pyrosetta.rosetta.core.scoring import ScoreType\n",
    "score = create_score_function('ref2015')\n",
    "score.set_weight(ScoreType.aa_composition, 1.0) # reweight score\n",
    "\n",
    "from pyrosetta.rosetta.protocols.aa_composition import AddCompositionConstraintMover\n",
    "add_comp_cst = AddCompositionConstraintMover()\n",
    "add_comp_cst.create_constraint_from_file('./data/aa_comp_constraint_file.comp')\n",
    "# add_comp_cst.add_residue_selector(selector) # 输入pose限制的范围, 如果缺省,那么将全pose限制氨基酸组成。\n",
    "add_comp_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5463b25e-7efa-434f-955e-2cf85a3cc09b",
   "metadata": {},
   "source": [
    "#### 2.2 AddNetChargeConstraintMover\n",
    "添加净电荷限制Mover,开始使用前,需要准备.charge限制文件。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "0f4c6e76-3bea-4874-a691-9151983047a2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.scoring.netcharge_energy.NetChargeEnergySetup: {0} \u001b[0mReading netcharge scoring term setup data from ./data/charge_comp_constraint_file.charge.\n",
      "\u001b[0mprotocols.aa_composition.AddNetChargeConstraintMover: {0} \u001b[0mInitialized NetChargeConstraint object from file ./data/charge_comp_constraint_file.charge.\n"
     ]
    }
   ],
   "source": [
    "from pyrosetta.rosetta.core.scoring import ScoreType\n",
    "score = create_score_function('ref2015')\n",
    "score.set_weight(ScoreType.netcharge, 1.0) # reweight score\n",
    "\n",
    "from pyrosetta.rosetta.protocols.aa_composition import AddNetChargeConstraintMover\n",
    "add_net_charge_cst = AddNetChargeConstraintMover()\n",
    "add_net_charge_cst.create_constraint_from_file('./data/charge_comp_constraint_file.charge')\n",
    "# add_net_charge_cst.add_residue_selector(selector) # 输入pose限制的范围, 如果缺省,那么将全pose限制氨基酸组成。\n",
    "add_net_charge_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "58e8a31f-d5cb-4d80-8bc0-32dba944da42",
   "metadata": {},
   "source": [
    "#### 2.3 ResidueTypeConstraintMover\n",
    "在Design时倾向于奖励某类氨基酸的能量得分。\n",
    "如当突变成Gly时 ddg=-1,突变成A的ddg=-1,那么经过ALA bonus约束(weight=2.0). 最后氨基酸序列输出时,选择了突变成A氨基酸的ddg为-2。 这是一种直接在packer中奖励residue序列得分全局的方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "0595e230-2422-4d3e-923e-a1f876bae0f1",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyrosetta.rosetta.protocols.constraint_movers import ResidueTypeConstraintMover\n",
    "aa_type_cst = ResidueTypeConstraintMover()\n",
    "aa_type_cst.set_AA_name3('ALA')\n",
    "aa_type_cst.set_favor_bonus(2.0) #权重\n",
    "aa_type_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d92ab30-eeca-42c4-a0ec-617cbd2129fb",
   "metadata": {},
   "source": [
    "### 三、使用Constraint Generators生成约束\n",
    "Constraint Generators不同于file文件系统,生成器可以自动地根据用户输入的参数进行约束参数生成,十分方便。\n",
    "\n",
    "**备注: 以下内容可能涉及ResidueSelector,介绍详见第五章节。**\n",
    "\n",
    "以下我们将介绍几种常用的自动生成器的使用方法:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c04670b-bc49-4829-b886-bf708138e9fa",
   "metadata": {},
   "source": [
    "#### 3.1 AddConstraints\n",
    "AddConstraintsMover可以使用多个constraint generator来生成一些列的限制,并且将他们添加到Pose中。\n",
    "\n",
    "后面将在例子中进行使用说明。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18e4f841-22ba-499a-831b-fe3ea4261d4f",
   "metadata": {},
   "source": [
    "#### 3.2 AtomPairConstraintGenerator\n",
    "在一个selector子集内部生成**遍历的Pair-wise的原子距离约束**。\n",
    "\n",
    "有两种使用模式:\n",
    "- 模式1: 在一个子集中生成距离限制"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a890f11e-42f2-4098-b820-e971fd290d05",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/1ubq_clean.pdb' automatically determined to be of type PDB\n"
     ]
    }
   ],
   "source": [
    "from pyrosetta.rosetta.protocols.simple_moves import VirtualRootMover\n",
    "\n",
    "# load pose from 1ubq_clean.pdb\n",
    "pose = pose_from_pdb(\"./data/1ubq_clean.pdb\")\n",
    "\n",
    "# 添加虚拟的root\n",
    "vr_mover = VirtualRootMover()\n",
    "vr_mover.apply(pose)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "0ad264c1-834a-45b6-bcd4-865214aeb983",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mprotocols.constraint_generator.AddConstraints: {0} \u001b[0mAdding 116 constraints generated by ConstraintGenerator named unnamed_constraint_generator\n"
     ]
    }
   ],
   "source": [
    "# Score reweight\n",
    "score = create_score_function('ref2015')\n",
    "score.set_weight(ScoreType.atom_pair_constraint, 1.0) # reweight constraint score\n",
    "\n",
    "# 定义生成器\n",
    "from pyrosetta.rosetta.protocols.constraint_generator import AtomPairConstraintGenerator\n",
    "atompair_cst = AtomPairConstraintGenerator()\n",
    "\n",
    "# 定义残基选择器\n",
    "from pyrosetta.rosetta.core.select.residue_selector import ChainSelector\n",
    "chain_selector = ChainSelector(1)\n",
    "\n",
    "# 结构设置\n",
    "atompair_cst.set_residue_selector(chain_selector)\n",
    "\n",
    "# 参数设置\n",
    "atompair_cst.set_ca_only(True)\n",
    "atompair_cst.set_max_distance(8) # 超出这个距离不添加限制;\n",
    "atompair_cst.set_min_seq_sep(6)  # 如果序列氨基酸号大于该值才添加限制。\n",
    "atompair_cst.set_sd(1.0) # distance constraint的标准误;\n",
    "atompair_cst.set_use_harmonic_function(True) # use harmonic function instead of SOG function\n",
    "\n",
    "# add AtomPairConstraintGenerator to pose;\n",
    "from pyrosetta.rosetta.protocols.constraint_generator import AddConstraints\n",
    "add_cst = AddConstraints()\n",
    "add_cst.add_generator(atompair_cst)\n",
    "add_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51f10725-b4df-4955-a523-8a59301194fa",
   "metadata": {},
   "source": [
    "- 模式2: 生成两个子集之间的距离限制"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "ed94e9d8-dcdd-41e0-93fd-c8df6e856c6d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/1ubq_clean.pdb' automatically determined to be of type PDB\n"
     ]
    }
   ],
   "source": [
    "from pyrosetta.rosetta.protocols.simple_moves import VirtualRootMover\n",
    "\n",
    "# load pose from 1ubq_clean.pdb\n",
    "pose = pose_from_pdb(\"./data/1ubq_clean.pdb\")\n",
    "\n",
    "# 添加虚拟的root\n",
    "vr_mover = VirtualRootMover()\n",
    "vr_mover.apply(pose)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "71330454-e973-4228-813e-9edcd776a3fa",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mprotocols.constraint_generator.AddConstraints: {0} \u001b[0mAdding 14 constraints generated by ConstraintGenerator named unnamed_constraint_generator\n"
     ]
    }
   ],
   "source": [
    "# Score reweight\n",
    "score = create_score_function('ref2015')\n",
    "score.set_weight(ScoreType.atom_pair_constraint, 1.0) # reweight constraint score\n",
    "\n",
    "# 定义生成器\n",
    "from pyrosetta.rosetta.protocols.constraint_generator import AtomPairConstraintGenerator\n",
    "atompair_cst = AtomPairConstraintGenerator()\n",
    "\n",
    "# 定义残基选择器\n",
    "from pyrosetta.rosetta.core.select.residue_selector import ResidueIndexSelector\n",
    "res1_selector = ResidueIndexSelector('1-10')\n",
    "res2_selector = ResidueIndexSelector('20-30')\n",
    "\n",
    "# 结构设置\n",
    "atompair_cst.set_residue_selector(res1_selector)\n",
    "atompair_cst.set_secondary_residue_selector(res2_selector) #生成两个selector之间的距离限制时需要,使用后,min_seq_sep将不起效。\n",
    "\n",
    "# 参数设置\n",
    "atompair_cst.set_ca_only(True)\n",
    "atompair_cst.set_max_distance(12) # 超出这个距离不添加限制;\n",
    "atompair_cst.set_sd(1.0) # distance constraint的标准误;\n",
    "atompair_cst.set_use_harmonic_function(True) # use harmonic function instead of SOG function\n",
    "\n",
    "# add AtomPairConstraintGenerator to pose;\n",
    "from pyrosetta.rosetta.protocols.constraint_generator import AddConstraints\n",
    "add_cst = AddConstraints()\n",
    "add_cst.add_generator(atompair_cst)\n",
    "add_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13443226-d19d-41b8-9d27-1483b520f608",
   "metadata": {},
   "source": [
    "#### 3.3 CoordinateConstraintGenerator\n",
    "在一个Selector子集内部生成坐标限制;\n",
    "\n",
    "注意: 需要使用pyrosetta.rosetta.protocols.simple_moves.VirtualRootMover加一个虚拟的root."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "33f07916-dc53-4d0c-96d1-c6223454f9a1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/1ubq_clean.pdb' automatically determined to be of type PDB\n"
     ]
    }
   ],
   "source": [
    "from pyrosetta.rosetta.protocols.simple_moves import VirtualRootMover\n",
    "\n",
    "# load pose from 1ubq_clean.pdb\n",
    "pose = pose_from_pdb(\"./data/1ubq_clean.pdb\")\n",
    "\n",
    "# 添加虚拟的root\n",
    "vr_mover = VirtualRootMover()\n",
    "vr_mover.apply(pose)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "810be351-ec86-4c85-8f1b-29a70080a344",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mprotocols.constraint_generator.AddConstraints: {0} \u001b[0mAdding 40 constraints generated by ConstraintGenerator named unnamed_constraint_generator\n"
     ]
    }
   ],
   "source": [
    "# Score reweight\n",
    "score = create_score_function('ref2015')\n",
    "score.set_weight(ScoreType.coordinate_constraint, 1.0) # reweight constraint score\n",
    "\n",
    "# 定义残基选择器\n",
    "from pyrosetta.rosetta.core.select.residue_selector import ResidueIndexSelector\n",
    "res1_selector = ResidueIndexSelector('1-10')\n",
    "\n",
    "\n",
    "# 定义坐标约束生成器\n",
    "from pyrosetta.rosetta.protocols.constraint_generator import CoordinateConstraintGenerator\n",
    "coordinate_cst = CoordinateConstraintGenerator()\n",
    "coordinate_cst.set_ca_only(False)\n",
    "coordinate_cst.set_reference_pose(pose)\n",
    "coordinate_cst.set_residue_selector(res1_selector)\n",
    "coordinate_cst.set_sidechain(False) # True = all重原子,False = 骨架重原子\n",
    "\n",
    "# 约束函数设定\n",
    "coordinate_cst.set_sd(1.0) # strength/deviation e.g. -relax:coord_cst_stdev\n",
    "\n",
    "# add AtomPairConstraintGenerator to pose;\n",
    "from pyrosetta.rosetta.protocols.constraint_generator import AddConstraints\n",
    "add_cst = AddConstraints()\n",
    "add_cst.add_generator(coordinate_cst)\n",
    "add_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b2f7c40-f396-40dd-8edf-0083867575a0",
   "metadata": {},
   "source": [
    "#### 3.4 DihedralConstraintGenerator\n",
    "基于骨架二面角(phi or psi or omega)自动生成约束的生成器, 默认使用CircularHarmonic函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "01af1469-1f57-445c-b0f8-8283d23a143d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/1ubq_clean.pdb' automatically determined to be of type PDB\n"
     ]
    }
   ],
   "source": [
    "from pyrosetta.rosetta.protocols.simple_moves import VirtualRootMover\n",
    "\n",
    "# load pose from 1ubq_clean.pdb\n",
    "pose = pose_from_pdb(\"./data/1ubq_clean.pdb\")\n",
    "\n",
    "# 添加虚拟的root\n",
    "vr_mover = VirtualRootMover()\n",
    "vr_mover.apply(pose)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "17d3e019-a3bc-4fc5-a238-74be9d06f9e5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mprotocols.constraint_generator.TerminiConstraintGenerator: {0} \u001b[0mConstraining atoms  atomno= 2 rsd= 1  and  atomno= 2 rsd= 76 , min_distance=8 max_distance=20\n",
      "\u001b[0mprotocols.constraint_generator.AddConstraints: {0} \u001b[0mAdding 1 constraints generated by ConstraintGenerator named unnamed_constraint_generator\n"
     ]
    }
   ],
   "source": [
    "from pyrosetta.rosetta.protocols.constraint_generator import DihedralConstraintGenerator\n",
    "from pyrosetta.rosetta.core.id import MainchainTorsionType\n",
    "\n",
    "# Score reweight\n",
    "score = create_score_function('ref2015')\n",
    "score.set_weight(ScoreType.dihedral_constraint, 1.0) # reweight score\n",
    "\n",
    "# \n",
    "dh_cst = DihedralConstraintGenerator()\n",
    "# dh_cst.set_residue_selector()  # 设置选择器\n",
    "dh_cst.set_sd_degree(7.0)  # 默认允许的最大变化角度\n",
    "dh_cst.set_torsion_type(MainchainTorsionType.phi_dihedral)  # phi_dihedral,psi_dihedral,omega_dihedral\n",
    "\n",
    "# add DihedralConstraintGenerator to pose;\n",
    "from pyrosetta.rosetta.protocols.constraint_generator import AddConstraints\n",
    "add_cst = AddConstraints()\n",
    "add_cst.add_generator(termin_cst)\n",
    "add_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed2fe0e3-3b36-4ead-b963-17d3e98f19ce",
   "metadata": {},
   "source": [
    "#### 3.5 TerminiConstraintGenerator\n",
    "生成N端和C端之间原子的限制参数。从PyRosetta API中看,仅仅是可以设置简单的距离限制。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "e4bb8448-089a-4878-adc2-5fd6145e3afa",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mcore.import_pose.import_pose: {0} \u001b[0mFile './data/1ubq_clean.pdb' automatically determined to be of type PDB\n"
     ]
    }
   ],
   "source": [
    "from pyrosetta.rosetta.protocols.simple_moves import VirtualRootMover\n",
    "\n",
    "# load pose from 1ubq_clean.pdb\n",
    "pose = pose_from_pdb(\"./data/1ubq_clean.pdb\")\n",
    "\n",
    "# 添加虚拟的root\n",
    "vr_mover = VirtualRootMover()\n",
    "vr_mover.apply(pose)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "7d540269-2f9b-466c-8f65-a02d567b9d6c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mprotocols.constraint_generator.TerminiConstraintGenerator: {0} \u001b[0mConstraining atoms  atomno= 2 rsd= 1  and  atomno= 2 rsd= 76 , min_distance=8 max_distance=20\n",
      "\u001b[0mprotocols.constraint_generator.AddConstraints: {0} \u001b[0mAdding 1 constraints generated by ConstraintGenerator named unnamed_constraint_generator\n"
     ]
    }
   ],
   "source": [
    "# Score reweight\n",
    "score = create_score_function('ref2015')\n",
    "score.set_weight(ScoreType.atom_pair_constraint, 1.0) # reweight score\n",
    "\n",
    "# \n",
    "from pyrosetta.rosetta.protocols.constraint_generator import TerminiConstraintGenerator\n",
    "termin_cst = TerminiConstraintGenerator()\n",
    "termin_cst.set_min_distance(8)\n",
    "termin_cst.set_max_distance(20)\n",
    "termin_cst.set_sd(1.0)\n",
    "\n",
    "# add TerminiConstraintGenerator to pose;\n",
    "from pyrosetta.rosetta.protocols.constraint_generator import AddConstraints\n",
    "add_cst = AddConstraints()\n",
    "add_cst.add_generator(termin_cst)\n",
    "add_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ca02fa96-c25d-47d8-a074-21e61b51ede2",
   "metadata": {},
   "source": [
    "#### 3.6 AutomaticSheetConstraintGenerator\n",
    "自动根据Pose中的beta sheet结构匹配,生成sheet间氢键的配对约束。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "f368efe5-0b38-4160-af2c-59cb733c27f8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mprotocols.constraint_generator.TerminiConstraintGenerator: {0} \u001b[0mConstraining atoms  atomno= 2 rsd= 1  and  atomno= 2 rsd= 76 , min_distance=8 max_distance=20\n",
      "\u001b[0mprotocols.constraint_generator.AddConstraints: {0} \u001b[0mAdding 1 constraints generated by ConstraintGenerator named unnamed_constraint_generator\n"
     ]
    }
   ],
   "source": [
    "from pyrosetta.rosetta.protocols.fold_from_loops.constraint_generator import AutomaticSheetConstraintGenerator\n",
    "# Score reweight\n",
    "score = create_score_function('ref2015')\n",
    "score.set_weight(ScoreType.atom_pair_constraint, 1.0) # reweight score\n",
    "\n",
    "sheet_g = AutomaticSheetConstraintGenerator()\n",
    "sheet_g.distance(12)\n",
    "sheet_g.sd(1.0)\n",
    "\n",
    "# add AutomaticSheetConstraintGenerator to pose;\n",
    "from pyrosetta.rosetta.protocols.constraint_generator import AddConstraints\n",
    "add_cst = AddConstraints()\n",
    "add_cst.add_generator(termin_cst)\n",
    "add_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2264926e-d05f-47cd-a64e-01b06fb1391b",
   "metadata": {},
   "source": [
    "### 四、清除Pose中的约束限制的方法"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f8688b84-7de9-4634-9818-10913c440242",
   "metadata": {},
   "source": [
    "#### 4.1 ReleaseConstraintFromResidueMover\n",
    "从Pose中清除selector中的氨基酸限制。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "b66526e1-8e9e-457d-8ba9-33137d8c2975",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyrosetta.rosetta.protocols.fold_from_loops.movers import ReleaseConstraintFromResidueMover\n",
    "from pyrosetta.rosetta.core.select.residue_selector import ChainSelector\n",
    "\n",
    "# 定义残基选择器\n",
    "chain_selector = ChainSelector(1)\n",
    "\n",
    "# 清除约束\n",
    "clean_selector_cst = ReleaseConstraintFromResidueMover(chain_selector)\n",
    "clean_selector_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0f5b743-837b-4abe-bce5-e6d9a2dd9b3d",
   "metadata": {},
   "source": [
    "#### 4.2 RemoveConstraints\n",
    "从Pose中清除由constraint generator生成的限制。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "d9a73657-308f-4d67-b8c1-49fcc3e07c7f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mprotocols.constraint_generator.TerminiConstraintGenerator: {0} \u001b[0mConstraining atoms  atomno= 2 rsd= 1  and  atomno= 2 rsd= 76 , min_distance=8 max_distance=20\n",
      "\u001b[0mprotocols.constraint_generator.AddConstraints: {0} \u001b[0mAdding 1 constraints generated by ConstraintGenerator named unnamed_constraint_generator\n",
      "\u001b[0mprotocols.constraint_generator.RemoveConstraints: {0} \u001b[0mRemoving 1 constraints from pose generated by unnamed_constraint_generator\n"
     ]
    }
   ],
   "source": [
    "# add TerminiConstraintGenerator to pose again;\n",
    "from pyrosetta.rosetta.protocols.constraint_generator import AddConstraints\n",
    "add_cst = AddConstraints()\n",
    "add_cst.add_generator(termin_cst)\n",
    "add_cst.apply(pose)\n",
    "\n",
    "\n",
    "from pyrosetta.rosetta.protocols.constraint_generator import RemoveConstraints\n",
    "rm_cst = RemoveConstraints()\n",
    "rm_cst.add_generator(termin_cst)  # termin_cst为之前定义的生成器;\n",
    "rm_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec015de8-a6ce-4d4d-9f0a-4ada2160fd72",
   "metadata": {},
   "source": [
    "#### 4.3 ClearConstraintsMover\n",
    "从Pose中清除所有的限制。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "6f3d8504-39de-40e5-a1e0-8cd64e4d0ab8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pyrosetta.rosetta.protocols.constraint_movers import ClearConstraintsMover\n",
    "clear_cst = ClearConstraintsMover()\n",
    "clear_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "067fe7bf-66b7-4708-95ae-ebe21cfdb10b",
   "metadata": {},
   "source": [
    "#### 4.4 ClearCompositionConstraintsMover\n",
    "从Pose中清除sequence constraint/net charge constraint."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "48e9c6b5-b655-4c2c-8cff-495b981d9da7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0mprotocols.aa_composition.ClearCompositionConstraintsMover: {0} \u001b[0mRemoved all sequence constraints from the pose.\n"
     ]
    }
   ],
   "source": [
    "from pyrosetta.rosetta.protocols.aa_composition import ClearCompositionConstraintsMover\n",
    "clear_seq_cst = ClearCompositionConstraintsMover()\n",
    "clear_seq_cst.apply(pose)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "15dbfc68-340d-48d3-ba28-52ef08030e74",
   "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": 5
}