| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
$HackaMol::VERSION = '0.052'; |
|
2
|
|
|
|
|
|
|
#ABSTRACT: HackaMol: Object-Oriented Library for Molecular Hacking |
|
3
|
|
|
|
|
|
|
use 5.008; |
|
4
|
11
|
|
|
11
|
|
1719356
|
use Moose; |
|
|
11
|
|
|
|
|
114
|
|
|
5
|
11
|
|
|
11
|
|
5445
|
use HackaMol::AtomGroup; |
|
|
11
|
|
|
|
|
3835257
|
|
|
|
11
|
|
|
|
|
76
|
|
|
6
|
11
|
|
|
11
|
|
79051
|
use HackaMol::Molecule; |
|
|
11
|
|
|
|
|
46
|
|
|
|
11
|
|
|
|
|
578
|
|
|
7
|
11
|
|
|
11
|
|
6737
|
use HackaMol::Atom; |
|
|
11
|
|
|
|
|
41
|
|
|
|
11
|
|
|
|
|
493
|
|
|
8
|
11
|
|
|
11
|
|
7506
|
use HackaMol::Bond; |
|
|
11
|
|
|
|
|
42
|
|
|
|
11
|
|
|
|
|
501
|
|
|
9
|
11
|
|
|
11
|
|
6231
|
use HackaMol::Angle; |
|
|
11
|
|
|
|
|
47
|
|
|
|
11
|
|
|
|
|
484
|
|
|
10
|
11
|
|
|
11
|
|
6452
|
use HackaMol::Dihedral; |
|
|
11
|
|
|
|
|
43
|
|
|
|
11
|
|
|
|
|
470
|
|
|
11
|
11
|
|
|
11
|
|
6461
|
use Math::Vector::Real; |
|
|
11
|
|
|
|
|
47
|
|
|
|
11
|
|
|
|
|
504
|
|
|
12
|
11
|
|
|
11
|
|
94
|
use namespace::autoclean; |
|
|
11
|
|
|
|
|
21
|
|
|
|
11
|
|
|
|
|
682
|
|
|
13
|
11
|
|
|
11
|
|
63
|
use MooseX::StrictConstructor; |
|
|
11
|
|
|
|
|
22
|
|
|
|
11
|
|
|
|
|
91
|
|
|
14
|
11
|
|
|
11
|
|
989
|
use Scalar::Util qw(refaddr); |
|
|
11
|
|
|
|
|
26
|
|
|
|
11
|
|
|
|
|
78
|
|
|
15
|
11
|
|
|
11
|
|
35359
|
use Carp; |
|
|
11
|
|
|
|
|
31
|
|
|
|
11
|
|
|
|
|
605
|
|
|
16
|
11
|
|
|
11
|
|
62
|
|
|
|
11
|
|
|
|
|
23
|
|
|
|
11
|
|
|
|
|
38526
|
|
|
17
|
|
|
|
|
|
|
has 'readline_func' => ( |
|
18
|
|
|
|
|
|
|
is => 'rw', |
|
19
|
|
|
|
|
|
|
isa => 'CodeRef', |
|
20
|
|
|
|
|
|
|
predicate => 'has_readline_func', |
|
21
|
|
|
|
|
|
|
clearer => 'clear_readline_func', |
|
22
|
|
|
|
|
|
|
); |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
with |
|
25
|
|
|
|
|
|
|
'HackaMol::Roles::NameRole', |
|
26
|
|
|
|
|
|
|
'HackaMol::Roles::MolReadRole', |
|
27
|
|
|
|
|
|
|
'HackaMol::Roles::PathRole', |
|
28
|
|
|
|
|
|
|
'HackaMol::Roles::ExeRole', |
|
29
|
|
|
|
|
|
|
'HackaMol::Roles::FileFetchRole', |
|
30
|
|
|
|
|
|
|
'HackaMol::Roles::NERFRole', |
|
31
|
|
|
|
|
|
|
'HackaMol::Roles::RcsbRole'; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
my $self = shift; |
|
34
|
|
|
|
|
|
|
my $pdbid = shift || croak "Croak on passing pdbid, e.g. 2cba"; |
|
35
|
1
|
|
|
1
|
1
|
241
|
my ($file) = $self->getstore_pdbid($pdbid); |
|
36
|
1
|
|
33
|
|
|
29
|
return $self->read_file_mol($file); |
|
37
|
0
|
|
|
|
|
0
|
} |
|
38
|
0
|
|
|
|
|
0
|
|
|
39
|
|
|
|
|
|
|
my $self = shift; |
|
40
|
|
|
|
|
|
|
my $file = shift; |
|
41
|
|
|
|
|
|
|
my $mol = shift or croak "must pass molecule to add coords to"; |
|
42
|
5
|
|
|
5
|
1
|
1659
|
|
|
43
|
5
|
|
|
|
|
12
|
my @atoms = $self->read_file_atoms($file); |
|
44
|
5
|
100
|
|
|
|
20
|
my @matoms = $mol->all_atoms; |
|
45
|
|
|
|
|
|
|
|
|
46
|
4
|
|
|
|
|
23
|
if ( scalar(@matoms) != scalar(@atoms) ) { |
|
47
|
4
|
|
|
|
|
188
|
croak "file_push_coords_mol> number of atoms not same"; |
|
48
|
|
|
|
|
|
|
} |
|
49
|
4
|
100
|
|
|
|
17
|
foreach my $i ( 0 .. $#atoms ) { |
|
50
|
1
|
|
|
|
|
32
|
if ( $matoms[$i]->Z != $atoms[$i]->Z ) { |
|
51
|
|
|
|
|
|
|
croak "file_push_coords_mol> atom mismatch"; |
|
52
|
3
|
|
|
|
|
12
|
} |
|
53
|
117
|
100
|
|
|
|
2159
|
$matoms[$i]->push_coords($_) foreach ( $atoms[$i]->all_coords ); |
|
54
|
1
|
|
|
|
|
30
|
} |
|
55
|
|
|
|
|
|
|
} |
|
56
|
116
|
|
|
|
|
3608
|
|
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# keeps the header, and a map of model_ids |
|
59
|
|
|
|
|
|
|
my $self = shift; |
|
60
|
|
|
|
|
|
|
my $file = shift; |
|
61
|
|
|
|
|
|
|
my ( $header, $atoms, $model_ids ) = $self->read_file_pdb_parts($file); |
|
62
|
|
|
|
|
|
|
return ( |
|
63
|
1
|
|
|
1
|
0
|
10
|
HackaMol::Molecule->new( |
|
64
|
1
|
|
|
|
|
3
|
name => $file, |
|
65
|
1
|
|
|
|
|
10
|
atoms => $atoms, |
|
66
|
|
|
|
|
|
|
info => $header, |
|
67
|
1
|
|
|
|
|
41
|
model_ids => $model_ids |
|
68
|
|
|
|
|
|
|
) |
|
69
|
|
|
|
|
|
|
); |
|
70
|
|
|
|
|
|
|
} |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
my $self = shift; |
|
73
|
|
|
|
|
|
|
my $file = shift; |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
my @atoms = $self->read_file_atoms($file); |
|
76
|
|
|
|
|
|
|
my $name = $file; |
|
77
|
6
|
|
|
6
|
1
|
95
|
return ( HackaMol::Molecule->new( name => $name, atoms => [@atoms] ) ); |
|
78
|
6
|
|
|
|
|
16
|
} |
|
79
|
|
|
|
|
|
|
|
|
80
|
6
|
|
|
|
|
38
|
my $self = shift; |
|
81
|
6
|
|
|
|
|
38
|
my $string = shift; |
|
82
|
6
|
|
|
|
|
424
|
my $format = shift or croak "must pass format: xyz, pdb, pdbqt, zmat, yaml"; |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
my @atoms = $self->read_string_atoms( $string, $format ); |
|
85
|
|
|
|
|
|
|
my $name = $format . ".mol"; |
|
86
|
6
|
|
|
6
|
0
|
905
|
return ( HackaMol::Molecule->new( name => $name, atoms => [@atoms] ) ); |
|
87
|
6
|
|
|
|
|
12
|
} |
|
88
|
6
|
50
|
|
|
|
21
|
|
|
89
|
|
|
|
|
|
|
|
|
90
|
6
|
|
|
|
|
36
|
#take a list of n, atoms; walk down list and generate bonds |
|
91
|
6
|
|
|
|
|
22
|
my $self = shift; |
|
92
|
6
|
|
|
|
|
209
|
my @atoms = @_; |
|
93
|
|
|
|
|
|
|
croak "<2 atoms passed to build_bonds" unless ( @atoms > 1 ); |
|
94
|
|
|
|
|
|
|
my @bonds; |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# build the bonds |
|
97
|
|
|
|
|
|
|
my $k = 0; |
|
98
|
4
|
|
|
4
|
1
|
182
|
while ( $k + 1 <= $#atoms ) { |
|
99
|
4
|
|
|
|
|
14
|
my $name = |
|
100
|
4
|
100
|
|
|
|
21
|
join( "_", map { _name_resid( $_, 'B' ) } @atoms[ $k .. $k + 1 ] ); |
|
101
|
3
|
|
|
|
|
7
|
push @bonds, |
|
102
|
|
|
|
|
|
|
HackaMol::Bond->new( |
|
103
|
|
|
|
|
|
|
name => $name, |
|
104
|
3
|
|
|
|
|
4
|
atoms => [ @atoms[ $k, $k + 1 ] ] |
|
105
|
3
|
|
|
|
|
10
|
); |
|
106
|
|
|
|
|
|
|
$k++; |
|
107
|
177
|
|
|
|
|
304
|
} |
|
|
354
|
|
|
|
|
526
|
|
|
108
|
177
|
|
|
|
|
3874
|
return (@bonds); |
|
109
|
|
|
|
|
|
|
} |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
#take a list of n, atoms; walk down list and generate angles |
|
113
|
177
|
|
|
|
|
380
|
my $self = shift; |
|
114
|
|
|
|
|
|
|
my @atoms = @_; |
|
115
|
3
|
|
|
|
|
31
|
croak "<3 atoms passed to build_angles" unless ( @atoms > 2 ); |
|
116
|
|
|
|
|
|
|
my @angles; |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
# build the angles |
|
119
|
|
|
|
|
|
|
my $k = 0; |
|
120
|
|
|
|
|
|
|
|
|
121
|
4
|
|
|
4
|
1
|
165
|
while ( $k + 2 <= $#atoms ) { |
|
122
|
4
|
|
|
|
|
12
|
my $name = |
|
123
|
4
|
100
|
|
|
|
17
|
join( "_", map { _name_resid( $_, 'A' ) } @atoms[ $k .. $k + 2 ] ); |
|
124
|
3
|
|
|
|
|
7
|
push @angles, |
|
125
|
|
|
|
|
|
|
HackaMol::Angle->new( |
|
126
|
|
|
|
|
|
|
name => $name, |
|
127
|
3
|
|
|
|
|
5
|
atoms => [ @atoms[ $k .. $k + 2 ] ] |
|
128
|
|
|
|
|
|
|
); |
|
129
|
3
|
|
|
|
|
10
|
$k++; |
|
130
|
|
|
|
|
|
|
} |
|
131
|
174
|
|
|
|
|
282
|
return (@angles); |
|
|
522
|
|
|
|
|
787
|
|
|
132
|
174
|
|
|
|
|
3566
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
my $atom = shift; |
|
135
|
|
|
|
|
|
|
my $default = shift; |
|
136
|
|
|
|
|
|
|
return ( $default . $atom->resid ) |
|
137
|
174
|
|
|
|
|
362
|
unless $atom->has_name; # this comes up when undefined atoms are passed |
|
138
|
|
|
|
|
|
|
return ( $atom->name . $atom->resid ); |
|
139
|
3
|
|
|
|
|
37
|
} |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
#take a list of n, atoms; walk down list and generate dihedrals |
|
143
|
1560
|
|
|
1560
|
|
1754
|
my $self = shift; |
|
144
|
1560
|
|
|
|
|
1790
|
my @atoms = @_; |
|
145
|
1560
|
100
|
|
|
|
36156
|
croak "<4 atoms passed to build_dihedrals" unless ( @atoms > 3 ); |
|
146
|
|
|
|
|
|
|
my @dihedrals; |
|
147
|
1040
|
|
|
|
|
19761
|
|
|
148
|
|
|
|
|
|
|
# build the dihedrals |
|
149
|
|
|
|
|
|
|
my $k = 0; |
|
150
|
|
|
|
|
|
|
while ( $k + 3 <= $#atoms ) { |
|
151
|
|
|
|
|
|
|
my $name = |
|
152
|
|
|
|
|
|
|
join( "_", map { _name_resid( $_, 'D' ) } @atoms[ $k .. $k + 3 ] ); |
|
153
|
4
|
|
|
4
|
1
|
208
|
push @dihedrals, |
|
154
|
4
|
|
|
|
|
12
|
HackaMol::Dihedral->new( |
|
155
|
4
|
100
|
|
|
|
28
|
name => $name, |
|
156
|
3
|
|
|
|
|
4
|
atoms => [ @atoms[ $k .. $k + 3 ] ] |
|
157
|
|
|
|
|
|
|
); |
|
158
|
|
|
|
|
|
|
$k++; |
|
159
|
3
|
|
|
|
|
7
|
} |
|
160
|
3
|
|
|
|
|
9
|
return (@dihedrals); |
|
161
|
|
|
|
|
|
|
} |
|
162
|
171
|
|
|
|
|
306
|
|
|
|
684
|
|
|
|
|
1039
|
|
|
163
|
171
|
|
|
|
|
3768
|
|
|
164
|
|
|
|
|
|
|
# group atoms by attribute |
|
165
|
|
|
|
|
|
|
# Z, name, bond_count, etc. |
|
166
|
|
|
|
|
|
|
my $self = shift; |
|
167
|
|
|
|
|
|
|
my $attr = shift; |
|
168
|
171
|
|
|
|
|
373
|
my @atoms = @_; |
|
169
|
|
|
|
|
|
|
|
|
170
|
3
|
|
|
|
|
37
|
my %group; |
|
171
|
|
|
|
|
|
|
foreach my $atom (@atoms) { |
|
172
|
|
|
|
|
|
|
push @{ $group{ $atom->$attr } }, $atom; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
my @atomgroups = |
|
176
|
|
|
|
|
|
|
map { HackaMol::AtomGroup->new( atoms => $group{$_} ) } sort |
|
177
|
16
|
|
|
16
|
1
|
24
|
keys(%group); |
|
178
|
16
|
|
|
|
|
24
|
|
|
179
|
16
|
|
|
|
|
72
|
return (@atomgroups); |
|
180
|
|
|
|
|
|
|
|
|
181
|
16
|
|
|
|
|
20
|
} |
|
182
|
16
|
|
|
|
|
25
|
|
|
183
|
1520
|
|
|
|
|
1648
|
|
|
|
1520
|
|
|
|
|
28569
|
|
|
184
|
|
|
|
|
|
|
# group atoms by attributes |
|
185
|
|
|
|
|
|
|
# Z, name, bond_count, etc. |
|
186
|
|
|
|
|
|
|
# keep splitting the groups until there are no more attributes |
|
187
|
16
|
|
|
|
|
94
|
my $self = shift; |
|
|
130
|
|
|
|
|
3023
|
|
|
188
|
|
|
|
|
|
|
my @attrs = @{ +shift }; |
|
189
|
|
|
|
|
|
|
my @atoms = @_; |
|
190
|
16
|
|
|
|
|
171
|
|
|
191
|
|
|
|
|
|
|
return () unless @attrs; |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
my @groups = ( HackaMol::AtomGroup->new( atoms => [@atoms] ) ); |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
foreach my $attr (@attrs) { |
|
196
|
|
|
|
|
|
|
my @local_groups; |
|
197
|
|
|
|
|
|
|
foreach my $group (@groups) { |
|
198
|
|
|
|
|
|
|
push @local_groups, |
|
199
|
1
|
|
|
1
|
1
|
3
|
$self->group_by_atom_attr( $attr, $group->all_atoms ); |
|
200
|
1
|
|
|
|
|
2
|
} |
|
|
1
|
|
|
|
|
5
|
|
|
201
|
1
|
|
|
|
|
20
|
@groups = @local_groups; |
|
202
|
|
|
|
|
|
|
} |
|
203
|
1
|
50
|
|
|
|
4
|
|
|
204
|
|
|
|
|
|
|
return (@groups); |
|
205
|
1
|
|
|
|
|
50
|
|
|
206
|
|
|
|
|
|
|
} |
|
207
|
1
|
|
|
|
|
5
|
|
|
208
|
2
|
|
|
|
|
2
|
|
|
209
|
2
|
|
|
|
|
7
|
# take atom group |
|
210
|
13
|
|
|
|
|
405
|
my $self = shift; |
|
211
|
|
|
|
|
|
|
my $mol = shift; |
|
212
|
|
|
|
|
|
|
my $fudge = shift; |
|
213
|
2
|
|
|
|
|
58
|
$fudge = 0.15 unless defined($fudge); |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
my @sulfs = $mol->select_group("Z 16")->all_atoms; |
|
216
|
1
|
|
|
|
|
13
|
return unless @sulfs; |
|
217
|
|
|
|
|
|
|
my $dcut = 2 * $sulfs[0]->covalent_radius + $fudge; |
|
218
|
|
|
|
|
|
|
my $nm = "S-S"; |
|
219
|
|
|
|
|
|
|
my $count = 1; |
|
220
|
|
|
|
|
|
|
my @bonds = (); |
|
221
|
|
|
|
|
|
|
foreach my $is ( 0 .. $#sulfs ) { |
|
222
|
|
|
|
|
|
|
my $at_i = $sulfs[$is]; |
|
223
|
1
|
|
|
1
|
1
|
467
|
foreach my $js ( $is + 1 .. $#sulfs ) { |
|
224
|
1
|
|
|
|
|
3
|
my $at_j = $sulfs[$js]; |
|
225
|
1
|
|
|
|
|
2
|
my $dist = $at_j->distance($at_i); |
|
226
|
1
|
50
|
|
|
|
4
|
if ( $dist <= $dcut ) { |
|
227
|
|
|
|
|
|
|
push @bonds, |
|
228
|
1
|
|
|
|
|
8
|
HackaMol::Bond->new( |
|
229
|
1
|
50
|
|
|
|
28
|
name => $nm . "_" . $count++, |
|
230
|
1
|
|
|
|
|
26
|
atoms => [ $at_i, $at_j ], |
|
231
|
1
|
|
|
|
|
3
|
); |
|
232
|
1
|
|
|
|
|
3
|
} |
|
233
|
1
|
|
|
|
|
2
|
} |
|
234
|
1
|
|
|
|
|
4
|
} |
|
235
|
27
|
|
|
|
|
34
|
return @bonds; |
|
236
|
27
|
|
|
|
|
52
|
} |
|
237
|
351
|
|
|
|
|
423
|
|
|
238
|
351
|
|
|
|
|
584
|
|
|
239
|
351
|
100
|
|
|
|
636
|
# to be deprecated |
|
240
|
9
|
|
|
|
|
201
|
# works fine for single disulfide bonds |
|
241
|
|
|
|
|
|
|
# but does not |
|
242
|
|
|
|
|
|
|
my $self = shift; |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
my @sulf = grep { $_->Z == 16 } @_; |
|
245
|
|
|
|
|
|
|
my @ss = $self->find_bonds_brute( |
|
246
|
|
|
|
|
|
|
bond_atoms => [@sulf], |
|
247
|
|
|
|
|
|
|
candidates => [@sulf], |
|
248
|
1
|
|
|
|
|
9
|
fudge => 0.15, # 0.45 is too large |
|
249
|
|
|
|
|
|
|
max_bonds => 1, |
|
250
|
|
|
|
|
|
|
); |
|
251
|
|
|
|
|
|
|
return @ss; |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
my $self = shift; |
|
255
|
|
|
|
|
|
|
my %args = @_; |
|
256
|
1
|
|
|
1
|
1
|
6
|
my @bond_atoms = @{ $args{bond_atoms} }; |
|
257
|
|
|
|
|
|
|
my @atoms = @{ $args{candidates} }; |
|
258
|
1
|
|
|
|
|
7
|
|
|
|
3009
|
|
|
|
|
53695
|
|
|
259
|
1
|
|
|
|
|
13
|
my $fudge = 0.45; |
|
260
|
|
|
|
|
|
|
my $max_bonds = 99; |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
$fudge = $args{fudge} if ( exists( $args{fudge} ) ); |
|
263
|
|
|
|
|
|
|
$max_bonds = $args{max_bonds} if ( exists( $args{max_bonds} ) ); |
|
264
|
|
|
|
|
|
|
|
|
265
|
1
|
|
|
|
|
9
|
my @init_bond_counts = map { $_->bond_count } ( @bond_atoms, @atoms ); |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
my @bonds; |
|
268
|
|
|
|
|
|
|
my %name; |
|
269
|
6
|
|
|
6
|
1
|
20
|
|
|
270
|
6
|
|
|
|
|
37
|
foreach my $at_i (@bond_atoms) { |
|
271
|
6
|
|
|
|
|
10
|
next if ( $at_i->bond_count >= $max_bonds ); |
|
|
6
|
|
|
|
|
14
|
|
|
272
|
6
|
|
|
|
|
9
|
my $cov_i = $at_i->covalent_radius; |
|
|
6
|
|
|
|
|
19
|
|
|
273
|
|
|
|
|
|
|
|
|
274
|
6
|
|
|
|
|
9
|
foreach my $at_j (@atoms) { |
|
275
|
6
|
|
|
|
|
11
|
next if ( refaddr($at_i) == refaddr($at_j) ); |
|
276
|
|
|
|
|
|
|
next if ( $at_j->bond_count >= $max_bonds ); |
|
277
|
6
|
100
|
|
|
|
14
|
my $cov_j = $at_j->covalent_radius; |
|
278
|
6
|
100
|
|
|
|
13
|
my $dist = $at_j->distance($at_i); |
|
279
|
|
|
|
|
|
|
|
|
280
|
6
|
|
|
|
|
15
|
if ( $dist <= $cov_i + $cov_j + $fudge ) { |
|
|
338
|
|
|
|
|
6212
|
|
|
281
|
|
|
|
|
|
|
my $nm = $at_i->symbol . "-" . $at_j->symbol; |
|
282
|
6
|
|
|
|
|
23
|
$name{$nm}++; |
|
283
|
|
|
|
|
|
|
push @bonds, |
|
284
|
|
|
|
|
|
|
HackaMol::Bond->new( |
|
285
|
6
|
|
|
|
|
14
|
name => "$nm\_" . $name{$nm}, |
|
286
|
37
|
100
|
|
|
|
715
|
atoms => [ $at_i, $at_j ], |
|
287
|
28
|
|
|
|
|
601
|
); |
|
288
|
|
|
|
|
|
|
$at_i->inc_bond_count; |
|
289
|
28
|
|
|
|
|
48
|
$at_j->inc_bond_count; |
|
290
|
1030
|
100
|
|
|
|
2099
|
} |
|
291
|
1002
|
100
|
|
|
|
19459
|
|
|
292
|
844
|
|
|
|
|
16589
|
} |
|
293
|
844
|
|
|
|
|
1599
|
} |
|
294
|
|
|
|
|
|
|
|
|
295
|
844
|
100
|
|
|
|
1837
|
my $i = 0; |
|
296
|
33
|
|
|
|
|
707
|
foreach my $at ( @bond_atoms, @atoms ) { |
|
297
|
33
|
|
|
|
|
68
|
$at->reset_bond_count; |
|
298
|
|
|
|
|
|
|
$at->inc_bond_count( $init_bond_counts[$i] ); |
|
299
|
|
|
|
|
|
|
$i++; |
|
300
|
33
|
|
|
|
|
737
|
} |
|
301
|
|
|
|
|
|
|
return (@bonds); |
|
302
|
|
|
|
|
|
|
|
|
303
|
33
|
|
|
|
|
1002
|
} |
|
304
|
33
|
|
|
|
|
845
|
|
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
# no pod yet |
|
307
|
|
|
|
|
|
|
# this method walks out from the two atoms in a bond and returns a group |
|
308
|
|
|
|
|
|
|
my $self = shift; |
|
309
|
|
|
|
|
|
|
my $mol = shift; |
|
310
|
6
|
|
|
|
|
14
|
my $bond = shift; |
|
311
|
6
|
|
|
|
|
13
|
my $iba = $bond->get_atoms(0)->iatom; |
|
312
|
338
|
|
|
|
|
8804
|
my $ibb = $bond->get_atoms(1)->iatom; |
|
313
|
338
|
|
|
|
|
8677
|
|
|
314
|
338
|
|
|
|
|
414
|
my $init = { |
|
315
|
|
|
|
|
|
|
$iba => 1, |
|
316
|
6
|
|
|
|
|
91
|
$ibb => 1, |
|
317
|
|
|
|
|
|
|
}; |
|
318
|
|
|
|
|
|
|
my $root = $ibb; |
|
319
|
|
|
|
|
|
|
my $rotation_indices = _qrotatable( $mol->atoms, $ibb, $init ); |
|
320
|
|
|
|
|
|
|
delete( $rotation_indices->{$iba} ); |
|
321
|
|
|
|
|
|
|
delete( $rotation_indices->{$ibb} ); |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
return ( |
|
324
|
0
|
|
|
0
|
0
|
0
|
HackaMol::AtomGroup->new( |
|
325
|
0
|
|
|
|
|
0
|
atoms => [ |
|
326
|
0
|
|
|
|
|
0
|
map { $mol->get_atoms($_) } |
|
327
|
0
|
|
|
|
|
0
|
keys %{$rotation_indices} |
|
328
|
0
|
|
|
|
|
0
|
] |
|
329
|
|
|
|
|
|
|
) |
|
330
|
0
|
|
|
|
|
0
|
); |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
} |
|
333
|
|
|
|
|
|
|
|
|
334
|
0
|
|
|
|
|
0
|
|
|
335
|
0
|
|
|
|
|
0
|
# args: two HackaMol::AtomGroup or HackaMol::Molecule with the same number of atoms |
|
336
|
0
|
|
|
|
|
0
|
# the atoms are assumed to be in the same order, that's it! |
|
337
|
0
|
|
|
|
|
0
|
# |
|
338
|
|
|
|
|
|
|
# uses all vectors (mvr) in group to calculate the rotation matrix, and translation vector |
|
339
|
|
|
|
|
|
|
# needed to superpose the second group on to the first group. |
|
340
|
|
|
|
|
|
|
# |
|
341
|
|
|
|
|
|
|
# a typical workflow will run this to get the rotation and translation and then the AtomGroupRole |
|
342
|
0
|
|
|
|
|
0
|
# rotate_translate method to actually do the coordinate transformation. |
|
343
|
0
|
|
|
|
|
0
|
# |
|
|
0
|
|
|
|
|
0
|
|
|
344
|
|
|
|
|
|
|
# the algorithm is lifted from Bio::PDB::Structure, which in turn implements |
|
345
|
|
|
|
|
|
|
# method from S. Kearsley, Acta Cryst. A45, 208-210 1989 |
|
346
|
|
|
|
|
|
|
# may not be very fast. better suited to PDL |
|
347
|
|
|
|
|
|
|
# |
|
348
|
|
|
|
|
|
|
# returns: |
|
349
|
|
|
|
|
|
|
# 1. rotation matrix [3 rows, each is a MVR , e.g. x' = row_1 * xyz] |
|
350
|
|
|
|
|
|
|
# 2. translation vector (MVR) |
|
351
|
|
|
|
|
|
|
# 3. rmsd |
|
352
|
|
|
|
|
|
|
# |
|
353
|
|
|
|
|
|
|
my $self = shift; |
|
354
|
|
|
|
|
|
|
my $g2 = shift; # switch order, function here vs method in Bio::PDB |
|
355
|
|
|
|
|
|
|
my $g1 = shift; |
|
356
|
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
my $nrd1 = $g1->count_atoms; |
|
358
|
|
|
|
|
|
|
my $nrd2 = $g2->count_atoms; |
|
359
|
|
|
|
|
|
|
die "superpose error: groups must have same number of atoms\n" |
|
360
|
|
|
|
|
|
|
unless ( $nrd1 == $nrd2 && $nrd1 > 0 ); |
|
361
|
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
my ( $x1, $y1, $z1 ); |
|
363
|
|
|
|
|
|
|
my ( $x2, $y2, $z2 ); |
|
364
|
|
|
|
|
|
|
my ( $xm, $ym, $zm ); |
|
365
|
|
|
|
|
|
|
my ( $xp, $yp, $zp ); |
|
366
|
|
|
|
|
|
|
my ( $Sxmxm, $Sxpxp, $Symym, $Sypyp, $Szmzm, $Szpzp ); |
|
367
|
|
|
|
|
|
|
my ( $Sxmym, $Sxmyp, $Sxpym, $Sxpyp ); |
|
368
|
|
|
|
|
|
|
my ( $Sxmzm, $Sxmzp, $Sxpzm, $Sxpzp ); |
|
369
|
|
|
|
|
|
|
my ( $Symzm, $Symzp, $Sypzm, $Sypzp ); |
|
370
|
1
|
|
|
1
|
1
|
6
|
|
|
371
|
1
|
|
|
|
|
3
|
my $gc1 = $g1->center; |
|
372
|
1
|
|
|
|
|
2
|
my $gc2 = $g2->center; # these are MVRs |
|
373
|
|
|
|
|
|
|
|
|
374
|
1
|
|
|
|
|
30
|
my @mvr1 = map { $_->xyz - $gc1 } $g1->all_atoms; |
|
375
|
1
|
|
|
|
|
28
|
my @mvr2 = map { $_->xyz - $gc2 } $g2->all_atoms; |
|
376
|
1
|
50
|
33
|
|
|
7
|
|
|
377
|
|
|
|
|
|
|
foreach my $i ( 0 .. $nrd1 - 1 ) { |
|
378
|
|
|
|
|
|
|
( $x1, $y1, $z1 ) = @{ $mvr1[$i] }; |
|
379
|
1
|
|
|
|
|
11
|
( $x2, $y2, $z2 ) = @{ $mvr2[$i] }; |
|
380
|
1
|
|
|
|
|
0
|
$xm = ( $x1 - $x2 ); |
|
381
|
1
|
|
|
|
|
0
|
$xp = ( $x1 + $x2 ); |
|
382
|
1
|
|
|
|
|
0
|
$ym = ( $y1 - $y2 ); |
|
383
|
1
|
|
|
|
|
0
|
$yp = ( $y1 + $y2 ); |
|
384
|
1
|
|
|
|
|
0
|
$zm = ( $z1 - $z2 ); |
|
385
|
1
|
|
|
|
|
0
|
$zp = ( $z1 + $z2 ); |
|
386
|
1
|
|
|
|
|
0
|
|
|
387
|
|
|
|
|
|
|
$Sxmxm += $xm * $xm; |
|
388
|
1
|
|
|
|
|
6
|
$Sxpxp += $xp * $xp; |
|
389
|
1
|
|
|
|
|
5
|
$Symym += $ym * $ym; |
|
390
|
|
|
|
|
|
|
$Sypyp += $yp * $yp; |
|
391
|
1
|
|
|
|
|
31
|
$Szmzm += $zm * $zm; |
|
|
7
|
|
|
|
|
16
|
|
|
392
|
1
|
|
|
|
|
31
|
$Szpzp += $zp * $zp; |
|
|
7
|
|
|
|
|
15
|
|
|
393
|
|
|
|
|
|
|
|
|
394
|
1
|
|
|
|
|
4
|
$Sxmym += $xm * $ym; |
|
395
|
7
|
|
|
|
|
6
|
$Sxmyp += $xm * $yp; |
|
|
7
|
|
|
|
|
13
|
|
|
396
|
7
|
|
|
|
|
9
|
$Sxpym += $xp * $ym; |
|
|
7
|
|
|
|
|
9
|
|
|
397
|
7
|
|
|
|
|
8
|
$Sxpyp += $xp * $yp; |
|
398
|
7
|
|
|
|
|
8
|
|
|
399
|
7
|
|
|
|
|
8
|
$Sxmzm += $xm * $zm; |
|
400
|
7
|
|
|
|
|
8
|
$Sxmzp += $xm * $zp; |
|
401
|
7
|
|
|
|
|
7
|
$Sxpzm += $xp * $zm; |
|
402
|
7
|
|
|
|
|
8
|
$Sxpzp += $xp * $zp; |
|
403
|
|
|
|
|
|
|
|
|
404
|
7
|
|
|
|
|
9
|
$Symzm += $ym * $zm; |
|
405
|
7
|
|
|
|
|
6
|
$Symzp += $ym * $zp; |
|
406
|
7
|
|
|
|
|
8
|
$Sypzm += $yp * $zm; |
|
407
|
7
|
|
|
|
|
8
|
$Sypzp += $yp * $zp; |
|
408
|
7
|
|
|
|
|
8
|
} |
|
409
|
7
|
|
|
|
|
8
|
|
|
410
|
|
|
|
|
|
|
my @m; |
|
411
|
7
|
|
|
|
|
7
|
$m[0] = $Sxmxm + $Symym + $Szmzm; |
|
412
|
7
|
|
|
|
|
7
|
$m[1] = $Sypzm - $Symzp; |
|
413
|
7
|
|
|
|
|
7
|
$m[2] = $Sxmzp - $Sxpzm; |
|
414
|
7
|
|
|
|
|
8
|
$m[3] = $Sxpym - $Sxmyp; |
|
415
|
|
|
|
|
|
|
$m[4] = $m[1]; |
|
416
|
7
|
|
|
|
|
7
|
$m[5] = $Sypyp + $Szpzp + $Sxmxm; |
|
417
|
7
|
|
|
|
|
6
|
$m[6] = $Sxmym - $Sxpyp; |
|
418
|
7
|
|
|
|
|
7
|
$m[7] = $Sxmzm - $Sxpzp; |
|
419
|
7
|
|
|
|
|
9
|
$m[8] = $m[2]; |
|
420
|
|
|
|
|
|
|
$m[9] = $m[6]; |
|
421
|
7
|
|
|
|
|
8
|
$m[10] = $Sxpxp + $Szpzp + $Symym; |
|
422
|
7
|
|
|
|
|
8
|
$m[11] = $Symzm - $Sypzp; |
|
423
|
7
|
|
|
|
|
7
|
$m[12] = $m[3]; |
|
424
|
7
|
|
|
|
|
8
|
$m[13] = $m[7]; |
|
425
|
|
|
|
|
|
|
$m[14] = $m[11]; |
|
426
|
|
|
|
|
|
|
$m[15] = $Sxpxp + $Sypyp + $Szmzm; |
|
427
|
1
|
|
|
|
|
2
|
|
|
428
|
1
|
|
|
|
|
3
|
#compute the egienvectors and eigenvalues of the matrix |
|
429
|
1
|
|
|
|
|
3
|
my ( $revec, $reval ) = &__diagonalize(@m); |
|
430
|
1
|
|
|
|
|
2
|
|
|
431
|
1
|
|
|
|
|
2
|
#the smallest eigenvalue is the rmsd for the optimal alignment |
|
432
|
1
|
|
|
|
|
2
|
my $rmsd = sqrt( abs( $reval->[0] ) / $nrd1 ); |
|
433
|
1
|
|
|
|
|
3
|
|
|
434
|
1
|
|
|
|
|
2
|
#fetch the optimal quaternion |
|
435
|
1
|
|
|
|
|
3
|
my @q; |
|
436
|
1
|
|
|
|
|
2
|
$q[0] = $revec->[0][0]; |
|
437
|
1
|
|
|
|
|
2
|
$q[1] = $revec->[1][0]; |
|
438
|
1
|
|
|
|
|
2
|
$q[2] = $revec->[2][0]; |
|
439
|
1
|
|
|
|
|
2
|
$q[3] = $revec->[3][0]; |
|
440
|
1
|
|
|
|
|
3
|
|
|
441
|
1
|
|
|
|
|
1
|
#construct the rotation matrix given by the quaternion |
|
442
|
1
|
|
|
|
|
2
|
my @mt; |
|
443
|
1
|
|
|
|
|
3
|
$mt[0] = $q[0] * $q[0] + $q[1] * $q[1] - $q[2] * $q[2] - $q[3] * $q[3]; |
|
444
|
|
|
|
|
|
|
$mt[1] = 2.0 * ( $q[1] * $q[2] - $q[0] * $q[3] ); |
|
445
|
|
|
|
|
|
|
$mt[2] = 2.0 * ( $q[1] * $q[3] + $q[0] * $q[2] ); |
|
446
|
1
|
|
|
|
|
4
|
|
|
447
|
|
|
|
|
|
|
$mt[3] = 2.0 * ( $q[2] * $q[1] + $q[0] * $q[3] ); |
|
448
|
|
|
|
|
|
|
$mt[4] = $q[0] * $q[0] - $q[1] * $q[1] + $q[2] * $q[2] - $q[3] * $q[3]; |
|
449
|
1
|
|
|
|
|
4
|
$mt[5] = 2.0 * ( $q[2] * $q[3] - $q[0] * $q[1] ); |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
$mt[6] = 2.0 * ( $q[3] * $q[1] - $q[0] * $q[2] ); |
|
452
|
1
|
|
|
|
|
1
|
$mt[7] = 2.0 * ( $q[3] * $q[2] + $q[0] * $q[1] ); |
|
453
|
1
|
|
|
|
|
3
|
$mt[8] = $q[0] * $q[0] - $q[1] * $q[1] - $q[2] * $q[2] + $q[3] * $q[3]; |
|
454
|
1
|
|
|
|
|
3
|
|
|
455
|
1
|
|
|
|
|
1
|
#compute the displacement vector |
|
456
|
1
|
|
|
|
|
2
|
my @vt; |
|
457
|
|
|
|
|
|
|
$vt[0] = |
|
458
|
|
|
|
|
|
|
$gc2->[0] - $mt[0] * $gc1->[0] - $mt[1] * $gc1->[1] - $mt[2] * $gc1->[2]; |
|
459
|
1
|
|
|
|
|
3
|
$vt[1] = |
|
460
|
1
|
|
|
|
|
3
|
$gc2->[1] - $mt[3] * $gc1->[0] - $mt[4] * $gc1->[1] - $mt[5] * $gc1->[2]; |
|
461
|
1
|
|
|
|
|
3
|
$vt[2] = |
|
462
|
1
|
|
|
|
|
3
|
$gc2->[2] - $mt[6] * $gc1->[0] - $mt[7] * $gc1->[1] - $mt[8] * $gc1->[2]; |
|
463
|
|
|
|
|
|
|
|
|
464
|
1
|
|
|
|
|
2
|
return ( [ V( @mt[ 0, 1, 2 ] ), V( @mt[ 3, 4, 5 ] ), V( @mt[ 6, 7, 8 ] ) ], |
|
465
|
1
|
|
|
|
|
3
|
V(@vt), $rmsd ); |
|
466
|
1
|
|
|
|
|
3
|
} |
|
467
|
|
|
|
|
|
|
|
|
468
|
1
|
|
|
|
|
4
|
my $self = shift; |
|
469
|
1
|
|
|
|
|
2
|
my $g1 = shift; # switch order, function here vs method in Bio::PDB |
|
470
|
1
|
|
|
|
|
4
|
my $g2 = shift; |
|
471
|
|
|
|
|
|
|
my $w = shift; |
|
472
|
|
|
|
|
|
|
|
|
473
|
1
|
|
|
|
|
2
|
my $nrd1 = $g1->count_atoms; |
|
474
|
1
|
|
|
|
|
4
|
my $nrd2 = $g2->count_atoms; |
|
475
|
|
|
|
|
|
|
die "rmsd error: groups must have same number of atoms\n" |
|
476
|
1
|
|
|
|
|
4
|
unless ( $nrd1 == $nrd2 && $nrd1 > 0 ); |
|
477
|
|
|
|
|
|
|
|
|
478
|
1
|
|
|
|
|
4
|
my @w; |
|
479
|
|
|
|
|
|
|
if ( defined($w) ) { |
|
480
|
|
|
|
|
|
|
@w = @{$w}; |
|
481
|
1
|
|
|
|
|
19
|
} |
|
482
|
|
|
|
|
|
|
else { |
|
483
|
|
|
|
|
|
|
@w = map { 1 } 0 .. $nrd1 - 1; |
|
484
|
|
|
|
|
|
|
} |
|
485
|
|
|
|
|
|
|
|
|
486
|
0
|
|
|
0
|
1
|
0
|
die "rmsd error: atom array weight must have same dimension as groups\n" |
|
487
|
0
|
|
|
|
|
0
|
unless ( $nrd1 == scalar(@w) ); |
|
488
|
0
|
|
|
|
|
0
|
my $sum_weights = |
|
489
|
0
|
|
|
|
|
0
|
0; # will be same as number of atoms if no weights are defined |
|
490
|
|
|
|
|
|
|
|
|
491
|
0
|
|
|
|
|
0
|
$sum_weights += $_ foreach @w; |
|
492
|
0
|
|
|
|
|
0
|
|
|
493
|
0
|
0
|
0
|
|
|
0
|
my @xyz_1 = map { $_->xyz } $g1->all_atoms; |
|
494
|
|
|
|
|
|
|
my @xyz_2 = map { $_->xyz } $g2->all_atoms; |
|
495
|
|
|
|
|
|
|
|
|
496
|
0
|
|
|
|
|
0
|
my $sqr_dev = 0; |
|
497
|
0
|
0
|
|
|
|
0
|
$sqr_dev += $w[$_] * $xyz_1[$_]->dist2( $xyz_2[$_] ) foreach 0 .. $#xyz_1; |
|
498
|
0
|
|
|
|
|
0
|
return sqrt( $sqr_dev / $sum_weights ); |
|
|
0
|
|
|
|
|
0
|
|
|
499
|
|
|
|
|
|
|
} |
|
500
|
|
|
|
|
|
|
|
|
501
|
0
|
|
|
|
|
0
|
my $atoms = shift; |
|
|
0
|
|
|
|
|
0
|
|
|
502
|
|
|
|
|
|
|
my $iroot = shift; |
|
503
|
|
|
|
|
|
|
my $visited = shift; |
|
504
|
0
|
0
|
|
|
|
0
|
|
|
505
|
|
|
|
|
|
|
$visited->{$iroot}++; |
|
506
|
0
|
|
|
|
|
0
|
|
|
507
|
|
|
|
|
|
|
if ( scalar( keys %$visited ) > 80 ) { |
|
508
|
|
|
|
|
|
|
carp "search too deep. exiting recursion"; |
|
509
|
0
|
|
|
|
|
0
|
return; |
|
510
|
|
|
|
|
|
|
} |
|
511
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
512
|
0
|
|
|
|
|
0
|
my @cands; |
|
|
0
|
|
|
|
|
0
|
|
|
513
|
|
|
|
|
|
|
foreach my $at (@$atoms) { |
|
514
|
0
|
|
|
|
|
0
|
push @cands, $at unless ( grep { $at->iatom == $_ } keys %{$visited} ); |
|
515
|
0
|
|
|
|
|
0
|
} |
|
516
|
0
|
|
|
|
|
0
|
|
|
517
|
|
|
|
|
|
|
#not calling in object context, hence the dummy 'self' |
|
518
|
|
|
|
|
|
|
my @bonds = find_bonds_brute( |
|
519
|
|
|
|
|
|
|
'self', |
|
520
|
0
|
|
|
0
|
|
0
|
bond_atoms => [ $atoms->[$iroot] ], |
|
521
|
0
|
|
|
|
|
0
|
candidates => [@cands], |
|
522
|
0
|
|
|
|
|
0
|
fudge => 0.45, |
|
523
|
|
|
|
|
|
|
); |
|
524
|
0
|
|
|
|
|
0
|
|
|
525
|
|
|
|
|
|
|
foreach my $cand ( map { $_->get_atoms(1) } @bonds ) { |
|
526
|
0
|
0
|
|
|
|
0
|
next if $visited->{ $cand->iatom }; |
|
527
|
0
|
|
|
|
|
0
|
my $visited = _qrotatable( $atoms, $cand->iatom, $visited ); |
|
528
|
0
|
|
|
|
|
0
|
} |
|
529
|
|
|
|
|
|
|
return ($visited); |
|
530
|
|
|
|
|
|
|
} |
|
531
|
0
|
|
|
|
|
0
|
|
|
532
|
0
|
|
|
|
|
0
|
#Jacobi diagonalizer |
|
533
|
0
|
0
|
|
|
|
0
|
my ( $onorm, $dnorm ); |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
534
|
|
|
|
|
|
|
my ( $b, $dma, $q, $t, $c, $s ); |
|
535
|
|
|
|
|
|
|
my ( $atemp, $vtemp, $dtemp ); |
|
536
|
|
|
|
|
|
|
my ( $i, $j, $k, $l ); |
|
537
|
0
|
|
|
|
|
0
|
my @a; |
|
538
|
|
|
|
|
|
|
my @v; |
|
539
|
|
|
|
|
|
|
my @d; |
|
540
|
|
|
|
|
|
|
my $nrot = 30; #number of sweeps |
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
for ( $i = 0 ; $i < 4 ; $i++ ) { |
|
543
|
|
|
|
|
|
|
for ( $j = 0 ; $j < 4 ; $j++ ) { |
|
544
|
0
|
|
|
|
|
0
|
$a[$i][$j] = $_[ 4 * $i + $j ]; |
|
|
0
|
|
|
|
|
0
|
|
|
545
|
0
|
0
|
|
|
|
0
|
$v[$i][$j] = 0.0; |
|
546
|
0
|
|
|
|
|
0
|
} |
|
547
|
|
|
|
|
|
|
} |
|
548
|
0
|
|
|
|
|
0
|
|
|
549
|
|
|
|
|
|
|
for ( $j = 0 ; $j <= 3 ; $j++ ) { |
|
550
|
|
|
|
|
|
|
$v[$j][$j] = 1.0; |
|
551
|
|
|
|
|
|
|
$d[$j] = $a[$j][$j]; |
|
552
|
|
|
|
|
|
|
} |
|
553
|
1
|
|
|
1
|
|
11
|
|
|
554
|
1
|
|
|
|
|
0
|
for ( $l = 1 ; $l <= $nrot ; $l++ ) { |
|
555
|
1
|
|
|
|
|
0
|
$dnorm = 0.0; |
|
556
|
1
|
|
|
|
|
0
|
$onorm = 0.0; |
|
557
|
1
|
|
|
|
|
0
|
for ( $j = 0 ; $j <= 3 ; $j++ ) { |
|
558
|
1
|
|
|
|
|
0
|
$dnorm += abs( $d[$j] ); |
|
559
|
1
|
|
|
|
|
0
|
for ( $i = 0 ; $i <= $j - 1 ; $i++ ) { |
|
560
|
1
|
|
|
|
|
2
|
$onorm += abs( $a[$i][$j] ); |
|
561
|
|
|
|
|
|
|
} |
|
562
|
1
|
|
|
|
|
4
|
} |
|
563
|
4
|
|
|
|
|
6
|
last if ( ( $onorm / $dnorm ) <= 1.0e-12 ); |
|
564
|
16
|
|
|
|
|
21
|
for ( $j = 1 ; $j <= 3 ; $j++ ) { |
|
565
|
16
|
|
|
|
|
27
|
for ( $i = 0 ; $i <= $j - 1 ; $i++ ) { |
|
566
|
|
|
|
|
|
|
$b = $a[$i][$j]; |
|
567
|
|
|
|
|
|
|
if ( abs($b) > 0.0 ) { |
|
568
|
|
|
|
|
|
|
$dma = $d[$j] - $d[$i]; |
|
569
|
1
|
|
|
|
|
4
|
if ( ( abs($dma) + abs($b) ) <= abs($dma) ) { |
|
570
|
4
|
|
|
|
|
5
|
$t = $b / $dma; |
|
571
|
4
|
|
|
|
|
8
|
} |
|
572
|
|
|
|
|
|
|
else { |
|
573
|
|
|
|
|
|
|
$q = 0.5 * $dma / $b; |
|
574
|
1
|
|
|
|
|
4
|
$t = 1.0 / ( abs($q) + sqrt( 1.0 + $q * $q ) ); |
|
575
|
1
|
|
|
|
|
1
|
$t *= -1.0 if ( $q < 0.0 ); |
|
576
|
1
|
|
|
|
|
2
|
} |
|
577
|
1
|
|
|
|
|
4
|
$c = 1.0 / sqrt( $t * $t + 1.0 ); |
|
578
|
4
|
|
|
|
|
6
|
$s = $t * $c; |
|
579
|
4
|
|
|
|
|
8
|
$a[$i][$j] = 0.0; |
|
580
|
6
|
|
|
|
|
11
|
for ( $k = 0 ; $k <= $i - 1 ; $k++ ) { |
|
581
|
|
|
|
|
|
|
$atemp = $c * $a[$k][$i] - $s * $a[$k][$j]; |
|
582
|
|
|
|
|
|
|
$a[$k][$j] = $s * $a[$k][$i] + $c * $a[$k][$j]; |
|
583
|
1
|
50
|
|
|
|
3
|
$a[$k][$i] = $atemp; |
|
584
|
0
|
|
|
|
|
0
|
} |
|
585
|
0
|
|
|
|
|
0
|
for ( $k = $i + 1 ; $k <= $j - 1 ; $k++ ) { |
|
586
|
0
|
|
|
|
|
0
|
$atemp = $c * $a[$i][$k] - $s * $a[$k][$j]; |
|
587
|
0
|
0
|
|
|
|
0
|
$a[$k][$j] = $s * $a[$i][$k] + $c * $a[$k][$j]; |
|
588
|
0
|
|
|
|
|
0
|
$a[$i][$k] = $atemp; |
|
589
|
0
|
0
|
|
|
|
0
|
} |
|
590
|
0
|
|
|
|
|
0
|
for ( $k = $j + 1 ; $k <= 3 ; $k++ ) { |
|
591
|
|
|
|
|
|
|
$atemp = $c * $a[$i][$k] - $s * $a[$j][$k]; |
|
592
|
|
|
|
|
|
|
$a[$j][$k] = $s * $a[$i][$k] + $c * $a[$j][$k]; |
|
593
|
0
|
|
|
|
|
0
|
$a[$i][$k] = $atemp; |
|
594
|
0
|
|
|
|
|
0
|
} |
|
595
|
0
|
0
|
|
|
|
0
|
for ( $k = 0 ; $k <= 3 ; $k++ ) { |
|
596
|
|
|
|
|
|
|
$vtemp = $c * $v[$k][$i] - $s * $v[$k][$j]; |
|
597
|
0
|
|
|
|
|
0
|
$v[$k][$j] = $s * $v[$k][$i] + $c * $v[$k][$j]; |
|
598
|
0
|
|
|
|
|
0
|
$v[$k][$i] = $vtemp; |
|
599
|
0
|
|
|
|
|
0
|
} |
|
600
|
0
|
|
|
|
|
0
|
$dtemp = |
|
601
|
0
|
|
|
|
|
0
|
$c * $c * $d[$i] + $s * $s * $d[$j] - 2.0 * $c * $s * $b; |
|
602
|
0
|
|
|
|
|
0
|
$d[$j] = |
|
603
|
0
|
|
|
|
|
0
|
$s * $s * $d[$i] + $c * $c * $d[$j] + 2.0 * $c * $s * $b; |
|
604
|
|
|
|
|
|
|
$d[$i] = $dtemp; |
|
605
|
0
|
|
|
|
|
0
|
} |
|
606
|
0
|
|
|
|
|
0
|
} |
|
607
|
0
|
|
|
|
|
0
|
} |
|
608
|
0
|
|
|
|
|
0
|
} |
|
609
|
|
|
|
|
|
|
$nrot = $l; |
|
610
|
0
|
|
|
|
|
0
|
for ( $j = 0 ; $j <= 2 ; $j++ ) { |
|
611
|
0
|
|
|
|
|
0
|
$k = $j; |
|
612
|
0
|
|
|
|
|
0
|
$dtemp = $d[$k]; |
|
613
|
0
|
|
|
|
|
0
|
for ( $i = $j + 1 ; $i <= 3 ; $i++ ) { |
|
614
|
|
|
|
|
|
|
if ( $d[$i] < $dtemp ) { |
|
615
|
0
|
|
|
|
|
0
|
$k = $i; |
|
616
|
0
|
|
|
|
|
0
|
$dtemp = $d[$k]; |
|
617
|
0
|
|
|
|
|
0
|
} |
|
618
|
0
|
|
|
|
|
0
|
} |
|
619
|
|
|
|
|
|
|
|
|
620
|
0
|
|
|
|
|
0
|
if ( $k > $j ) { |
|
621
|
|
|
|
|
|
|
$d[$k] = $d[$j]; |
|
622
|
0
|
|
|
|
|
0
|
$d[$j] = $dtemp; |
|
623
|
|
|
|
|
|
|
for ( $i = 0 ; $i <= 3 ; $i++ ) { |
|
624
|
0
|
|
|
|
|
0
|
$dtemp = $v[$i][$k]; |
|
625
|
|
|
|
|
|
|
$v[$i][$k] = $v[$i][$j]; |
|
626
|
|
|
|
|
|
|
$v[$i][$j] = $dtemp; |
|
627
|
|
|
|
|
|
|
} |
|
628
|
|
|
|
|
|
|
} |
|
629
|
1
|
|
|
|
|
3
|
} |
|
630
|
1
|
|
|
|
|
4
|
|
|
631
|
3
|
|
|
|
|
4
|
return ( \@v, \@d ); |
|
632
|
3
|
|
|
|
|
4
|
} |
|
633
|
3
|
|
|
|
|
6
|
|
|
634
|
6
|
50
|
|
|
|
13
|
__PACKAGE__->meta->make_immutable; |
|
635
|
0
|
|
|
|
|
0
|
|
|
636
|
0
|
|
|
|
|
0
|
1; |
|
637
|
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
=pod |
|
640
|
3
|
50
|
|
|
|
7
|
|
|
641
|
0
|
|
|
|
|
0
|
=head1 NAME |
|
642
|
0
|
|
|
|
|
0
|
|
|
643
|
0
|
|
|
|
|
0
|
HackaMol - HackaMol: Object-Oriented Library for Molecular Hacking |
|
644
|
0
|
|
|
|
|
0
|
|
|
645
|
0
|
|
|
|
|
0
|
=head1 VERSION |
|
646
|
0
|
|
|
|
|
0
|
|
|
647
|
|
|
|
|
|
|
version 0.052 |
|
648
|
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
650
|
|
|
|
|
|
|
|
|
651
|
1
|
|
|
|
|
4
|
The L<HackaMol publication|http://pubs.acs.org/doi/abs/10.1021/ci500359e> has |
|
652
|
|
|
|
|
|
|
a more complete description of the library (L<pdf available from researchgate|http://www.researchgate.net/profile/Demian_Riccardi/publication/273778191_HackaMol_an_object-oriented_Modern_Perl_library_for_molecular_hacking_on_multiple_scales/links/550ebec60cf27526109e6ade.pdf>). |
|
653
|
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
Citation: J. Chem. Inf. Model., 2015, 55, 721 |
|
655
|
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
Loading the HackaMol library in a script with |
|
657
|
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
use HackaMol; |
|
659
|
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
provides attributes and methods of a builder class. It also loads all the |
|
661
|
|
|
|
|
|
|
classes provided by the core so including them is not necessary, e.g.: |
|
662
|
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
use HackaMol::Atom; |
|
664
|
|
|
|
|
|
|
use HackaMol::Bond; |
|
665
|
|
|
|
|
|
|
use HackaMol::Angle; |
|
666
|
|
|
|
|
|
|
use HackaMol::Dihedral; |
|
667
|
|
|
|
|
|
|
use HackaMol::AtomGroup; |
|
668
|
|
|
|
|
|
|
use HackaMol::Molecule; |
|
669
|
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
The methods, described below, facilitate the creation of objects from files and |
|
671
|
|
|
|
|
|
|
other objects. It is a builder class that evolves more rapidly than the classes for the molecular objects. |
|
672
|
|
|
|
|
|
|
For example, the superpose_rt and rmsd methods will likely be moved to a more suitable class or |
|
673
|
|
|
|
|
|
|
functional module. |
|
674
|
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
=head1 METHODS |
|
676
|
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
=head2 pdbid_mol |
|
678
|
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
one argument: pdbid |
|
680
|
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
This method will download the pdb, unless it exists, and load it into a |
|
682
|
|
|
|
|
|
|
HackaMol::Molecule object. For example, |
|
683
|
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
my $mol = HackaMol->new->pdbid_mol('2cba'); |
|
685
|
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
=head2 read_file_atoms |
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
one argument: filename. |
|
689
|
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
This method parses the file (e.g. file.xyz, file.pdb) and returns an |
|
691
|
|
|
|
|
|
|
array of HackaMol::Atom objects. It uses the filename postfix to decide which parser to use. e.g. file.pdb will |
|
692
|
|
|
|
|
|
|
trigger the pdb parser. |
|
693
|
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
=head2 read_file_mol |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
one argument: filename. |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
This method parses the file (e.g. file.xyz, file.pdb) and returns a |
|
699
|
|
|
|
|
|
|
HackaMol::Molecule object. |
|
700
|
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
=head2 read_file_push_coords_mol |
|
702
|
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
two arguments: filename and a HackaMol::Molecule object. |
|
704
|
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
This method reads the coordinates from a file and pushes them into the atoms |
|
706
|
|
|
|
|
|
|
contained in the molecule. Thus, the atoms in the molecule and the atoms in |
|
707
|
|
|
|
|
|
|
the file must be the same. |
|
708
|
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
=head2 build_bonds |
|
710
|
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
takes a list of atoms and returns a list of bonds. The bonds are generated for |
|
712
|
|
|
|
|
|
|
"list neighbors" by simply stepping through the atom list one at a time. e.g. |
|
713
|
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
my @bonds = $hack->build_bonds(@atoms[1,3,5]); |
|
715
|
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
will return two bonds: B13 and B35 |
|
717
|
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=head2 build_angles |
|
719
|
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
takes a list of atoms and returns a list of angles. The angles are generated |
|
721
|
|
|
|
|
|
|
analagously to build_bonds, e.g. |
|
722
|
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
my @angles = $hack->build_angles(@atoms[1,3,5]); |
|
724
|
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
will return one angle: A135 |
|
726
|
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
=head2 build_dihedrals |
|
728
|
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
takes a list of atoms and returns a list of dihedrals. The dihedrals are generated |
|
730
|
|
|
|
|
|
|
analagously to build_bonds, e.g. |
|
731
|
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
my @dihedral = $hack->build_dihedrals(@atoms[1,3,5]); |
|
733
|
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
will croak! you need atleast four atoms. |
|
735
|
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
my @dihedral = $hack->build_dihedrals(@atoms[1,3,5,6,9]); |
|
737
|
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
will return two dihedrals: D1356 and D3569 |
|
739
|
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
=head2 group_by_atom_attr |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
args: atom attribute (e.g. 'name') ; list of atoms (e.g. $mol->all_atoms) |
|
743
|
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
returns array of AtomGroup objects |
|
745
|
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
=head2 group_by_atom_attrs |
|
747
|
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
args: array reference of multiple atom attributes (e.g. ['resname', 'chain' ]); list of atoms. |
|
749
|
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
returns array of AtomGroup objects |
|
751
|
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
=head2 find_bonds_brute |
|
753
|
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
The arguments are key_value pairs of bonding criteria (see example below). |
|
755
|
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
This method returns bonds between bond_atoms and the candidates using the |
|
757
|
|
|
|
|
|
|
criteria (many of wich have defaults). |
|
758
|
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
my @oxy_bonds = $hack->find_bonds_brute( |
|
760
|
|
|
|
|
|
|
bond_atoms => [$hg], |
|
761
|
|
|
|
|
|
|
candidates => [$mol->all_atoms], |
|
762
|
|
|
|
|
|
|
fudge => 0.45, |
|
763
|
|
|
|
|
|
|
max_bonds => 6, |
|
764
|
|
|
|
|
|
|
); |
|
765
|
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
fudge is optional with Default is 0.45 (open babel uses same default); |
|
767
|
|
|
|
|
|
|
max_bonds is optional with default of 99. max_bonds is compared against |
|
768
|
|
|
|
|
|
|
the atom bond count, which are incremented during the search. Before returning |
|
769
|
|
|
|
|
|
|
the bonds, the bond_count are returned the values before the search. For now, |
|
770
|
|
|
|
|
|
|
molecules are responsible for setting the number of bonds in atoms. |
|
771
|
|
|
|
|
|
|
find_bonds_brute uses a bruteforce algorithm that tests the interatomic |
|
772
|
|
|
|
|
|
|
separation against the sum of the covalent radii + fudge. It will not test |
|
773
|
|
|
|
|
|
|
for bond between atoms if either atom has >= max_bonds. It does not return |
|
774
|
|
|
|
|
|
|
a self bond for an atom (C< next if refaddr($ati) == refaddr($atj) >). |
|
775
|
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
=head2 mol_disulfide_bonds |
|
777
|
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
my @ss = $bldr->mol_disulfide_bonds($mol, [$fudge]); # default $fudge = 0.15 |
|
779
|
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
Returns all disulfide bonds with lengths leq 2 x S->covalent_radius + $fudge. $mol can be an AtomGroup |
|
781
|
|
|
|
|
|
|
or Molecule. |
|
782
|
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
=head2 find_disulfide_bonds |
|
784
|
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
my @ss = $bldr->find_disulfide_bonds(@atoms); |
|
786
|
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
DEPRECATED. Uses find_bonds_brute with fudge of 0.15 and max_bonds 1. mol_disulfides was developed |
|
788
|
|
|
|
|
|
|
after finding funky cysteine clusters (e.g. 1f3h) |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
=head2 rmsd ($group1,$group2,$weights) |
|
791
|
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
my $rmsd = $bldr->rmsd($group1, $group2, [$weights]); #optional weights need to be tested |
|
793
|
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
Computes the root mean square deviation between atomic vectors of the two AtomGroup/Molecule objects. |
|
795
|
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
=head2 superpose_rt ($group1, $group2) |
|
797
|
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
WARNING: 1. needs more testing (feel free to contribute tests!). 2. may shift to another class. |
|
799
|
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
args: two hackmol objects (HackaMol::AtomGroup or HackaMol::Molecule) with same number of atoms. |
|
801
|
|
|
|
|
|
|
This method is intended to be very flexible. It does not check meta data of the atoms, it just pulls |
|
802
|
|
|
|
|
|
|
the vectors in each group to calculate the rotation matrix and translation vector needed to superpose |
|
803
|
|
|
|
|
|
|
the second set on to the first set. |
|
804
|
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
The vectors assumed to be in the same order, that's it! |
|
806
|
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
A typical workflow: |
|
808
|
|
|
|
|
|
|
|
|
809
|
|
|
|
|
|
|
my $bb1 = $mol1->select_group('backbone'); |
|
810
|
|
|
|
|
|
|
my $bb2 = $mol2->select_group('backbone'); |
|
811
|
|
|
|
|
|
|
my ($rmat,$trans,$rmsd) = HackaMol->new()->superpose_rt($bb1,$bb2); |
|
812
|
|
|
|
|
|
|
# $rmsd is the RMSD between backbones |
|
813
|
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
# to calculate rmsd between other atoms after the backbone alignment |
|
815
|
|
|
|
|
|
|
$mol2->rotate_translate($rmat,$trans); |
|
816
|
|
|
|
|
|
|
my $total_rmsd = HackaMol->new()->rmsd($mol1,$mol2); |
|
817
|
|
|
|
|
|
|
# $total_rmsd is from all atoms in each mol |
|
818
|
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
the algorithm is lifted from Bio::PDB::Structure, which implements |
|
820
|
|
|
|
|
|
|
algorithm from S. Kearsley, Acta Cryst. A45, 208-210 1989 |
|
821
|
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
returns: |
|
823
|
|
|
|
|
|
|
1. rotation matrix [3 rows, each is a MVR , e.g. x' = row_1 * xyz] |
|
824
|
|
|
|
|
|
|
2. translation vector (MVR) |
|
825
|
|
|
|
|
|
|
3. rmsd |
|
826
|
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
|
828
|
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
=head2 name |
|
830
|
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
name is a rw str provided by HackaMol::NameRole. |
|
832
|
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
=head2 readline_func |
|
834
|
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
hook to add control to parsing files |
|
836
|
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
HackaMol->new( |
|
838
|
|
|
|
|
|
|
readline_func => sub {return "PDB_SKIP" unless /LYS/ } |
|
839
|
|
|
|
|
|
|
) |
|
840
|
|
|
|
|
|
|
->pdbid_mol("2cba") |
|
841
|
|
|
|
|
|
|
->print_pdb; # will parse lysines because the PDB reader looks for the PDB_SKIP return value |
|
842
|
|
|
|
|
|
|
|
|
843
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
844
|
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
# simple example: load pdb file and extract the disulfide bonds |
|
846
|
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
use HackaMol; |
|
848
|
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
my $bldr = HackaMol->new( name => 'builder'); |
|
850
|
|
|
|
|
|
|
my $mol = $bldr->pdbid_mol('1kni'); |
|
851
|
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
my @disulfide_bonds = $bldr->find_disulfide_bonds( $mol->all_atoms ); |
|
853
|
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
print $_->dump foreach @disulfide_bonds; |
|
855
|
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
See the above executed in this L<linked notebook|https://github.com/demianriccardi/p5-IPerl-Notebooks/blob/master/HackaMol/HackaMol-Synopsis.ipynb> |
|
857
|
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
859
|
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
=over 4 |
|
861
|
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
=item * |
|
863
|
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
L<HackaMol::Atom> |
|
865
|
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
=item * |
|
867
|
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
L<HackaMol::Bond> |
|
869
|
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
=item * |
|
871
|
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
L<HackaMol::Angle> |
|
873
|
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
=item * |
|
875
|
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
L<HackaMol::Dihedral> |
|
877
|
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
=item * |
|
879
|
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
L<HackaMol::AtomGroup> |
|
881
|
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
=item * |
|
883
|
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
L<HackaMol::Molecule> |
|
885
|
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
=item * |
|
887
|
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
L<HackaMol::X::Calculator> |
|
889
|
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
=item * |
|
891
|
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
L<HackaMol::X::Vina> |
|
893
|
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
=item * |
|
895
|
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
L<Protein Data Bank|http://pdb.org> |
|
897
|
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
=item * |
|
899
|
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
L<VMD|http://www.ks.uiuc.edu/Research/vmd/> |
|
901
|
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
=item * |
|
903
|
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
L<Bio3D|http://thegrantlab.org/bio3d/> |
|
905
|
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
=item * |
|
907
|
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
L<MDAnalysis|https://www.mdanalysis.org/> |
|
909
|
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
=item * |
|
911
|
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
L<MDTraj|https://www.mdtraj.org/1.9.8.dev0/index.html> |
|
913
|
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
=back |
|
915
|
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
=head1 AUTHOR's PERSPECTIVE |
|
917
|
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
Over the years, I have found HackaMol most expeditious wrt testing out ideas |
|
919
|
|
|
|
|
|
|
or whipping up setups and analyses for thousands of molecules each with |
|
920
|
|
|
|
|
|
|
several thousand atoms. This is the realm of varied systems (lots of molecules |
|
921
|
|
|
|
|
|
|
often from the protein databank). For the analysis of MD simulations that hit |
|
922
|
|
|
|
|
|
|
the next order of magnitude wrt numbers of atoms and frames, I use other tools (such as |
|
923
|
|
|
|
|
|
|
the python library, MDAnalysis). This is the realm where the system (molecular make-up) |
|
924
|
|
|
|
|
|
|
varies more slowly often with modeled solvent potentially with millions of simulated frames. The future |
|
925
|
|
|
|
|
|
|
development of HackaMol will seek to remain in its lane and better serve that space. |
|
926
|
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
Perl is forever flexible and powerful; |
|
928
|
|
|
|
|
|
|
HackaMol has the potential to be a broadly useful tool in this region of |
|
929
|
|
|
|
|
|
|
molecular information, which is often dirty and not well-specified. Once |
|
930
|
|
|
|
|
|
|
the object system is stable in the Perl core, I plan to rework HackaMol to |
|
931
|
|
|
|
|
|
|
remove dependencies and improve performance. However, this tool will most |
|
932
|
|
|
|
|
|
|
likely never advance to the realm of analyzing molecular dynamics simulations. |
|
933
|
|
|
|
|
|
|
For the analysis of MD simulations with explicit solvent, please look into |
|
934
|
|
|
|
|
|
|
the python libraries MDAnalysis and MDTraj. |
|
935
|
|
|
|
|
|
|
Bio3D, in R, is also very cool and able to nicely handle simulation data for |
|
936
|
|
|
|
|
|
|
biological molecules stripped of solvent. In my view, Bio3D |
|
937
|
|
|
|
|
|
|
seems to fill the space between HackaMol and MD simulations with explicit solvent. |
|
938
|
|
|
|
|
|
|
These suggested tools are only the ones I am familiar with; |
|
939
|
|
|
|
|
|
|
I'm sure there are other very cool tools out there! |
|
940
|
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
=head1 EXTENDS |
|
942
|
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
=over 4 |
|
944
|
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
=item * L<Moose::Object> |
|
946
|
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
=back |
|
948
|
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
=head1 CONSUMES |
|
950
|
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
=over 4 |
|
952
|
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::ExeRole> |
|
954
|
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::FileFetchRole> |
|
956
|
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::MolReadRole> |
|
958
|
|
|
|
|
|
|
|
|
959
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::NERFRole> |
|
960
|
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::NameRole> |
|
962
|
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::NameRole|HackaMol::Roles::MolReadRole|HackaMol::Roles::PathRole|HackaMol::Roles::ExeRole|HackaMol::Roles::FileFetchRole|HackaMol::Roles::NERFRole|HackaMol::Roles::RcsbRole> |
|
964
|
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::PathRole> |
|
966
|
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::RcsbRole> |
|
968
|
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::ReadPdbRole> |
|
970
|
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::ReadPdbqtRole> |
|
972
|
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::ReadPdbxRole> |
|
974
|
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::ReadXyzRole> |
|
976
|
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::ReadYAMLRole> |
|
978
|
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::ReadYAMLRole|HackaMol::Roles::ReadZmatRole|HackaMol::Roles::ReadPdbRole|HackaMol::Roles::ReadPdbxRole|HackaMol::Roles::ReadPdbqtRole|HackaMol::Roles::ReadXyzRole> |
|
980
|
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
=item * L<HackaMol::Roles::ReadZmatRole> |
|
982
|
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
=back |
|
984
|
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
=head1 AUTHOR |
|
986
|
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
Demian Riccardi <demianriccardi@gmail.com> |
|
988
|
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
990
|
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
This software is copyright (c) 2017 by Demian Riccardi. |
|
992
|
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
|
994
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
|
995
|
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
=cut |