|
| 1 | +# !/usr/bin/env python3 |
| 2 | + |
| 3 | +""" |
| 4 | +rmsds-align.py: Calcuate 2D RMSD using different alignment and rmsd selections. |
| 5 | +
|
| 6 | +
|
| 7 | +The purpose of this tool is to calcuate pairwise RMSD for a selection after |
| 8 | +aligning using a different selection. This script supports upto 2 trajectories. |
| 9 | +
|
| 10 | +Anees Mohammmed Keedakkatt Puthenpeedikakkal, 2022 |
| 11 | +""" |
| 12 | + |
| 13 | +""" |
| 14 | +
|
| 15 | + This file is part of LOOS. |
| 16 | +
|
| 17 | + LOOS (Lightweight Object-Oriented Structure library) |
| 18 | + Copyright (c) 2013 Tod Romo, Grossfield Lab |
| 19 | + Department of Biochemistry and Biophysics |
| 20 | + School of Medicine & Dentistry, University of Rochester |
| 21 | +
|
| 22 | + This package (LOOS) is free software: you can redistribute it and/or modify |
| 23 | + it under the terms of the GNU General Public License as published by |
| 24 | + the Free Software Foundation under version 3 of the License. |
| 25 | +
|
| 26 | + This package is distributed in the hope that it will be useful, |
| 27 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 28 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 29 | + GNU General Public License for more details. |
| 30 | +
|
| 31 | + You should have received a copy of the GNU General Public License |
| 32 | + along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 33 | +
|
| 34 | +""" |
| 35 | + |
| 36 | + |
| 37 | +import sys |
| 38 | +import argparse |
| 39 | +import loos |
| 40 | +import loos.pyloos |
| 41 | + |
| 42 | + |
| 43 | +def fullhelp(): |
| 44 | + print(""" |
| 45 | +SYNOPSIS |
| 46 | +
|
| 47 | +Calculate a pair-wise RMSD for a trajectory (or two trajectories) with |
| 48 | +different align and rmsd selections. |
| 49 | +
|
| 50 | +
|
| 51 | +DESCRIPTION |
| 52 | +
|
| 53 | +This tool calculates the pairwise RMSD between each structures in a trajectory |
| 54 | +after aligning using a selection which is different from the RMSD selection. |
| 55 | +This tool can be used for two different trajectories also. This tool is similar |
| 56 | +to rmsds, except rmsds uses same selection for alignment and pairwise |
| 57 | +RMSD calculation. |
| 58 | +
|
| 59 | +The transformation matrix that aligns align_selection_2 is used to transform |
| 60 | +align_selection_1, followed by RMSD calcuation using rmsd_selection_1 to |
| 61 | +rmsd_selection_2. This is looped over the all the frames in the |
| 62 | +trajectory (or for selected --range1 and --range2) |
| 63 | +
|
| 64 | +EXAMPLES |
| 65 | +
|
| 66 | +python3 rmsds-align.py model.pdb simulation.dcd > rmsd.asc |
| 67 | +
|
| 68 | +This example uses all alpha-carbons and every frame in the trajectory |
| 69 | +(equivalent to rmsds). |
| 70 | +
|
| 71 | +
|
| 72 | +python3 rmsds-align.py --model2 inactive.pdb --traj2 inactive.dcd active.pdb |
| 73 | +active.dcd > rmsd.asc |
| 74 | +
|
| 75 | +This example uses all alpha-carbons and compares the "inactive" simulation |
| 76 | +with the "active" one. |
| 77 | +
|
| 78 | +
|
| 79 | +python3 rmsds-align.py --align 'resid <= 20 && name== "CA"' --rmsd 'resid > 25 |
| 80 | + && name =~ "^(C|CA|CB|O|N)$"' model.pdb simulation.dcd > rmsd.asc |
| 81 | +
|
| 82 | +This example uses only first 20 alpha carbons for alignment and pairwise RMSD |
| 83 | +is calculated for all the backbone atoms with resid > 25. |
| 84 | +
|
| 85 | +
|
| 86 | +python3 rmsds-align.py --align 'resid <= 20 && name== "CA"' --align2 |
| 87 | +'resid >=25 && resid <=44 && name == "CA"' --rmsd 'resid > 25 && resid < 50 && |
| 88 | +name =~ "^(C|CA|CB|O|N)$"' --rmsd2 'resid < 25 && name =~ "^(C|CA|CB|O|N)$"' |
| 89 | +--model2 inactive.pdb --traj2 inactive.dcd active.pdb active.dcd > rmsd.asc |
| 90 | +
|
| 91 | +This complex example first aligns active’s first 20 alpha-Cs with inactive’s |
| 92 | +alpha-Cs with resid >=25 and resid <=44. Pairwise RMSD is calculated between |
| 93 | +active’s backbone (with resid’s in 25-49) and inactive’s backbone with |
| 94 | +resid <25. |
| 95 | +
|
| 96 | +
|
| 97 | +NOTES |
| 98 | +
|
| 99 | +When using two trajectories, the selections must match both in number of atoms |
| 100 | +selected and in the sequence of atoms (i.e. the first atom in the align/rmsd |
| 101 | +selection is matched with the first atom in the align2/rmsd2 selection.) |
| 102 | +
|
| 103 | +SEE ALSO |
| 104 | +rmsd2ref, rmsds |
| 105 | +
|
| 106 | + """) |
| 107 | + |
| 108 | + |
| 109 | +class FullHelp(argparse.Action): |
| 110 | + def __init__(self, option_strings, dest, nargs=None, **kwargs): |
| 111 | + kwargs['nargs'] = 0 |
| 112 | + super(FullHelp, self).__init__(option_strings, dest, **kwargs) |
| 113 | + |
| 114 | + def __call__(self, parser, namespace, values, option_string=None): |
| 115 | + fullhelp() |
| 116 | + parser.print_help() |
| 117 | + setattr(namespace, self.dest, True) |
| 118 | + parser.exit() |
| 119 | + |
| 120 | + |
| 121 | +header = " ".join(sys.argv) |
| 122 | +parser = argparse.ArgumentParser(description="Calculate 2D RMSD using" |
| 123 | + " different alignment and rmsd selections.") |
| 124 | + |
| 125 | +parser.add_argument('model', help="Model") |
| 126 | + |
| 127 | +parser.add_argument('traj', help="Trajectory") |
| 128 | + |
| 129 | +parser.add_argument('--model2', |
| 130 | + help="Model for 2nd trajectory (default = model)", |
| 131 | + default=None) |
| 132 | + |
| 133 | +parser.add_argument('--traj2', |
| 134 | + help="2nd trajectory (default = traj)", |
| 135 | + default=None) |
| 136 | + |
| 137 | +parser.add_argument('--align', |
| 138 | + help="Align selection for 1st trajectory (default = CA)", |
| 139 | + default='name == "CA"', type=str) |
| 140 | + |
| 141 | +parser.add_argument('--align2', |
| 142 | + help="Align selection 2nd trajectory (default = align)", |
| 143 | + default=None, type=str) |
| 144 | + |
| 145 | +parser.add_argument('--rmsd', |
| 146 | + help="RMSD selection for 1st trajectory" |
| 147 | + "(default = (C|O|N|CA))", |
| 148 | + default='name =~ "^(C|O|N|CA)$"', type=str) |
| 149 | + |
| 150 | +parser.add_argument('--rmsd2', |
| 151 | + help="RMSD selection for 2nd trajectory (default = rmsd)", |
| 152 | + default=None, type=str) |
| 153 | + |
| 154 | +parser.add_argument('--precision', |
| 155 | + help="Write out matrix coefficients with this many digits " |
| 156 | + "(default = 2)", default=2, type=int) |
| 157 | + |
| 158 | +parser.add_argument('--range1', |
| 159 | + help="Range of frames to use from the first trajectory " |
| 160 | + "[FORMAT - skip:stride:stop, stop is optional] " |
| 161 | + "(default = 0:1:last)", default='0:1', type=str) |
| 162 | + |
| 163 | +parser.add_argument('--range2', help="Range of frames to use from the second " |
| 164 | + "trajectory [FORMAT - skip:stride:stop, stop is optional] " |
| 165 | + "(default = range1)", |
| 166 | + default=None, type=str) |
| 167 | + |
| 168 | +parser.add_argument('--fullhelp', |
| 169 | + help="Print detailed description of all options", |
| 170 | + action=FullHelp) |
| 171 | + |
| 172 | +args = parser.parse_args() |
| 173 | + |
| 174 | +# In case of only one trajectory is given as input |
| 175 | +if args.rmsd2 is None: |
| 176 | + args.rmsd2 = args.rmsd |
| 177 | + |
| 178 | +if args.align2 is None: |
| 179 | + args.align2 = args.align |
| 180 | + |
| 181 | +if args.model2 is None: |
| 182 | + args.model2 = args.model |
| 183 | + |
| 184 | +if args.traj2 is None: |
| 185 | + args.traj2 = args.traj |
| 186 | + |
| 187 | +if args.range2 is None: |
| 188 | + args.range2 = args.range1 |
| 189 | + |
| 190 | + |
| 191 | +# Organizing range of frames to consider in trajectories |
| 192 | +range_1 = args.range1.split(":") |
| 193 | +range_2 = args.range2.split(":") |
| 194 | + |
| 195 | +# In case only skip and stride is given as input for traj |
| 196 | +if len(range_1) == 2: |
| 197 | + select_1 = range(int(range_1[0]), len(args.traj), int(range_1[1])) |
| 198 | +# In case only skip, stride and stop are given |
| 199 | +elif len(range_1) == 3: |
| 200 | + select_1 = range(int(range_1[0]), int(range_1[2]), int(range_1[1])) |
| 201 | +else: |
| 202 | + print("Error in range") |
| 203 | + sys.exit(0) |
| 204 | + |
| 205 | + |
| 206 | +# In case only skip and stride is given as input for traj2 |
| 207 | +if len(range_1) == 2: |
| 208 | + select_2 = range(int(range_2[0]), len(args.traj2), int(range_2[1])) |
| 209 | +# In case only skip, stride and stop are given |
| 210 | +elif len(range_1) == 3: |
| 211 | + select_2 = range(int(range_2[0]), int(range_2[2]), int(range_2[1])) |
| 212 | +else: |
| 213 | + print("Error in range") |
| 214 | + sys.exit(0) |
| 215 | + |
| 216 | +# Model and Trajectory |
| 217 | +model = loos.createSystem(args.model) |
| 218 | +traj = loos.pyloos.Trajectory(args.traj, model, iterator=select_1) |
| 219 | +model2 = loos.createSystem(args.model2) |
| 220 | +traj2 = loos.pyloos.Trajectory(args.traj2, model2, iterator=select_2) |
| 221 | + |
| 222 | +# Align and RMSD selection definitions |
| 223 | +align_selection_1 = loos.selectAtoms(model, args.align) |
| 224 | +align_selection_2 = loos.selectAtoms(model2, args.align2) |
| 225 | + |
| 226 | +rmsd_selection_1 = loos.selectAtoms(model, args.rmsd) |
| 227 | +rmsd_selection_2 = loos.selectAtoms(model2, args.rmsd2) |
| 228 | + |
| 229 | +# Print input |
| 230 | +print("#", header) |
| 231 | + |
| 232 | + |
| 233 | +for frame in traj: |
| 234 | + ref_align = align_selection_1.copy() |
| 235 | + ref_target = rmsd_selection_1.copy() |
| 236 | + |
| 237 | + for frame in traj2: |
| 238 | + # Find transformation matrix that aligns align_selection_2 |
| 239 | + # onto ref_align(align_selection_1) |
| 240 | + trans_matrix = ref_align.alignOnto(align_selection_2) |
| 241 | + # Tranform matrix |
| 242 | + transform = loos.XForm(trans_matrix) |
| 243 | + # Apply the tranform to ref_target(rmsd_selection_1) |
| 244 | + ref_target.applyTransform(transform) |
| 245 | + # Calculate the RMSD between rmsd_selection_2 and |
| 246 | + # ref_target(rmsd_selection_1) |
| 247 | + rmsd_value = rmsd_selection_2.rmsd(ref_target) |
| 248 | + # Print RMSD |
| 249 | + print(round(rmsd_value, args.precision), "", end='') |
| 250 | + |
| 251 | + print("") |
0 commit comments