Skip to content

Commit 9812c73

Browse files
authored
2DRMSD (#56)
* Add files via upload 2drmsd.py script to calculate 2D RMSD after aligning with a different selection. * Update and rename 2drmsd.py to rmsds-align.py * Update rmsds-align.py * Update rmsds-align.py * Update rmsds-align.py Print header instead of lines 229-235.
1 parent 76a96bc commit 9812c73

File tree

1 file changed

+251
-0
lines changed

1 file changed

+251
-0
lines changed

Packages/Clustering/rmsds-align.py

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
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

Comments
 (0)