TMol How-To Guide — Advanced Kinematics#
7. Advanced kinematics#
Named torsions (phi/psi/chi, already used since section 1) exist for nucleic acids and ligands too. The FoldForest that section 2 treated as a black box is itself just a small, directly-constructible data structure — both get covered in more depth here.
Setup#
Wheel install, imports, seeding, and device selection live in notebook_setup.py.
[1]:
try:
import google.colab # noqa: F401
except ImportError:
IN_COLAB = False
else:
IN_COLAB = True
if IN_COLAB:
from urllib.request import urlretrieve
urlretrieve(
"https://raw.githubusercontent.com/RosettaCommons/tmol/"
"main/docs/tutorial/notebook_setup.py",
"notebook_setup.py",
)
from notebook_setup import * # noqa: F401,F403
device, param_db = setup()
Environment variable CCD_MIRROR_PATH not set. Will not be able to use function requiring this variable. To set it you may:
(1) add the line 'export VAR_NAME=path/to/variable' to your .bashrc or .zshrc file
(2) set it in your current shell with 'export VAR_NAME=path/to/variable'
(3) write it to a .env file in the root of the atomworks.io repository
Environment variable PDB_MIRROR_PATH not set. Will not be able to use function requiring this variable. To set it you may:
(1) add the line 'export VAR_NAME=path/to/variable' to your .bashrc or .zshrc file
(2) set it in your current shell with 'export VAR_NAME=path/to/variable'
(3) write it to a .env file in the root of the atomworks.io repository
Named torsions#
Querying and setting by name: protein, NA#
tmol.get_torsion_names/get_named_torsions/set_named_torsions are generic – they work on any residue type’s declared torsions, protein or nucleic acid alike. 1BNA (B-form DNA, from section 3) declares the standard backbone torsions (alpha through zeta), the glycosidic chi1, and the sugar-pucker torsions nu0/nu1/nu4.
[2]:
dna_cif_text = fetch_cif("1BNA")
dna_pose_stack = pose_stack_from_file(io.StringIO(dna_cif_text), device, param_db=param_db)
dna_block = 2
print("torsion names:", tmol.get_torsion_names(dna_pose_stack, 0, dna_block))
before_alpha = tmol.get_named_torsions(dna_pose_stack, 0, dna_block, 'alpha')
print(f"alpha: {before_alpha:.1f} deg")
viewer = tmol.view(dna_pose_stack)
viewer.show()
rotated_dna = tmol.set_named_torsions(dna_pose_stack, 0, dna_block, "alpha", 180.0)
after_alpha = tmol.get_named_torsions(rotated_dna, 0, dna_block, 'alpha')
print(f"alpha after setting to 180: {after_alpha:.1f} deg")
display(tmol.overlay_view(
{"original": dna_pose_stack, "alpha rotated": rotated_dna},
notes={"original": f"alpha={before_alpha:.1f} deg", "alpha rotated": f"alpha={after_alpha:.1f} deg"},
))
DG is seen only at a chain terminus and N1, N2 could each carry its other connection; none of them is a conventional backbone, so it cannot be told apart. A copy of the residue in a chain would settle it.
torsion names: ['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'chi1', 'nu0', 'nu1', 'nu4']
alpha: -62.6 deg
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
alpha after setting to 180: -180.0 deg
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))
“Autogenerated” named torsions for ligands#
A prepared ligand’s rotatable bonds become named torsions too, continuing the chi{n} numbering scheme – not the same names its chemistry would suggest (phi/psi don’t apply), just chi1, chi2, … in whatever order the bonds were discovered. 3PTB’s benzamidine is too small and rigid to have any (zero named torsions); the “ace” ligand fixture from section 4’s splitting example is larger and has several.
[3]:
import biotite.structure as struc
import biotite.structure.io
from tmol.io import pose_stack_from_atom_array
ligand_structure = biotite.structure.io.load_structure(
str(data_path("protein_ligand_test", "ace.tmol.nomin.cif")), model=1, include_bonds=True
)
if isinstance(ligand_structure, struc.AtomArrayStack):
ligand_structure = ligand_structure[0]
ligand_pose_stack = pose_stack_from_atom_array(
ligand_structure, device, prepare_ligands=True,
ligand_params_files=[str(data_path("protein_ligand_test", "ace.xtal-lig.mmff94.tmol"))], no_optH=True, param_db=param_db,
)
ligand_block = next(
block for block in range(ligand_pose_stack.max_n_blocks)
if ligand_pose_stack.block_type(0, block).name3 == "LG1"
)
ligand_torsion_names = tmol.get_torsion_names(ligand_pose_stack, 0, ligand_block)
print(f"ligand torsion names: {ligand_torsion_names}")
print(f"chi1: {tmol.get_named_torsions(ligand_pose_stack, 0, ligand_block, 'chi1'):.1f} deg")
viewer = tmol.view(ligand_pose_stack)
viewer.show()
ligand torsion names: ['chi1', 'chi2', 'chi3', 'chi4', 'chi5', 'chi6', 'chi7', 'chi8', 'chi9', 'chi10', 'chi11', 'chi12', 'chi13']
chi1: -61.0 deg
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
FoldForest basic concepts#
A FoldForest is a small set of directed edges describing how a kinematic tree connects a structure’s blocks – tmol.kinematics.EdgeType.polymer (a contiguous run of blocks), .jump (an arbitrary connection between two residues), and .root_jump (an edge from the tree’s virtual root into one residue, start=-1). tmol.FoldForest.reasonable_fold_forest(pose_stack) builds one automatically, rooting each chain at its first residue – an N-to-C tree per chain, which every example
so far has used implicitly.
Manipulating a FoldForest explicitly#
FoldForest.from_edges builds one from a padded [pose, edge, 4] array of (edge_type, start, end, jump_index) tuples. A small peptide, rooted at its first residue as usual:
[4]:
peptide = tmol.extended_pose_stack_from_sequences("AKLFG", device=device)
viewer = tmol.view(peptide)
viewer.show()
last_block = peptide.max_n_blocks - 1
n_to_c_edges = np.zeros((1, 2, 4), dtype=np.int64)
n_to_c_edges[0, 0] = [tmol.EdgeType.root_jump, -1, 0, -1]
n_to_c_edges[0, 1] = [tmol.EdgeType.polymer, 0, last_block, -1]
n_to_c_fold_forest = tmol.FoldForest.from_edges(n_to_c_edges)
print("N->C fold forest matches the automatic one:", (n_to_c_edges == tmol.FoldForest.reasonable_fold_forest(peptide).edges).all())
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))
3Dmol.js failed to load for some reason. Please check your browser console for error messages.
N->C fold forest matches the automatic one: True
Rooting the same peptide at its last residue instead, with the polymer edge running backward, gives a C-to-N tree.
[5]:
c_to_n_edges = np.zeros((1, 2, 4), dtype=np.int64)
c_to_n_edges[0, 0] = [tmol.EdgeType.root_jump, -1, last_block, -1]
c_to_n_edges[0, 1] = [tmol.EdgeType.polymer, last_block, 0, -1]
c_to_n_fold_forest = tmol.FoldForest.from_edges(c_to_n_edges)
print("built a C->N fold forest with", int(c_to_n_fold_forest.n_edges[0]), "edges")
built a C->N fold forest with 2 edges
set_named_torsions takes an optional fold_forest= to move along a tree other than the pose’s default – it moves whichever side of the torsion’s bond is downstream of the root, so the two trees reach the same torsion value by moving opposite ends of the chain.
[6]:
middle_block = 2
targets = {"phi": -61.0, "psi": -43.0}
moved_n_to_c = tmol.set_named_torsions(peptide, 0, middle_block, list(targets), list(targets.values()))
moved_c_to_n = tmol.set_named_torsions(
peptide, 0, middle_block, list(targets), list(targets.values()), fold_forest=c_to_n_fold_forest
)
for name, target in targets.items():
print(
f"{name}: target {target:.1f}, N->C tree {tmol.get_named_torsions(moved_n_to_c, 0, middle_block, name):.1f}, "
f"C->N tree {tmol.get_named_torsions(moved_c_to_n, 0, middle_block, name):.1f}"
)
first_block_offset = int(peptide.block_coord_offset64[0, 1])
last_block_offset = int(peptide.block_coord_offset64[0, last_block])
moved_before = (moved_n_to_c.coords[0, :first_block_offset] - peptide.coords[0, :first_block_offset]).norm(dim=-1)
moved_after = (moved_c_to_n.coords[0, last_block_offset:] - peptide.coords[0, last_block_offset:]).norm(dim=-1)
print(f"N->C tree leaves the N-terminal residue fixed: max move {float(torch.nan_to_num(moved_before).max()):.5f} A")
print(f"C->N tree leaves the C-terminal residue fixed: max move {float(torch.nan_to_num(moved_after).max()):.5f} A")
display(tmol.overlay_view(
{"original": peptide, "N->C tree": moved_n_to_c, "C->N tree": moved_c_to_n},
notes={
"original": "unmoved peptide",
"N->C tree": f"N-terminus fixed, max move {float(torch.nan_to_num(moved_before).max()):.5f} A",
"C->N tree": f"C-terminus fixed, max move {float(torch.nan_to_num(moved_after).max()):.5f} A",
},
))
phi: target -61.0, N->C tree -61.0, C->N tree -61.0
psi: target -43.0, N->C tree -43.0, C->N tree -43.0
N->C tree leaves the N-terminal residue fixed: max move 0.00000 A
C->N tree leaves the C-terminal residue fixed: max move 0.00000 A
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))
/home/runner/work/tmol/tmol/.venv/lib/python3.12/site-packages/biotite/structure/io/pdb/file.py:629: DeprecationWarning: The chararray class is deprecated and will be removed in a future release. Use an ndarray with a string or bytes dtype instead.
record = np.char.array(np.where(array.hetero, "HETATM", "ATOM"))