Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2016-2023 The plumed team
3 : (see the PEOPLE file at the root of the distribution for a list of names)
4 :
5 : See http://www.plumed.org for more information.
6 :
7 : This file is part of plumed, version 2.
8 :
9 : plumed is free software: you can redistribute it and/or modify
10 : it under the terms of the GNU Lesser General Public License as published by
11 : the Free Software Foundation, either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : plumed is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU Lesser General Public License for more details.
18 :
19 : You should have received a copy of the GNU Lesser General Public License
20 : along with plumed. If not, see <http://www.gnu.org/licenses/>.
21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 :
23 : /*
24 : This vast majority of the source code in this file was writting by
25 : Sandro Bottaro with some help from Giovanni Bussi
26 : */
27 :
28 : #include "ERMSD.h"
29 : #include "PDB.h"
30 : #include "Matrix.h"
31 : #include "Tensor.h"
32 :
33 : #include "Pbc.h"
34 : #include <array>
35 : #include <cmath>
36 : #include <iostream>
37 :
38 :
39 : namespace PLMD {
40 :
41 0 : void ERMSD::clear() {
42 : reference_mat.clear();
43 0 : }
44 :
45 : //void ERMSD::calcLcs(const vector<Vector> & positions, vector<Vector> &)
46 :
47 4 : void ERMSD::setReference(const std::vector<Vector> & reference, const std::vector<unsigned> & pairs_vec, double mycutoff) {
48 :
49 4 : natoms = reference.size();
50 4 : nresidues = natoms/3;
51 4 : unsigned npairs = pairs_vec.size()/2;
52 4 : pairs.resize(npairs);
53 16 : for(unsigned i=0; i<npairs; ++i) {
54 :
55 12 : pairs[i].first = pairs_vec[2*i];
56 12 : pairs[i].second = pairs_vec[2*i+1];
57 : }
58 :
59 4 : cutoff = mycutoff;
60 : std::vector<TensorGeneric<4,3> > deri;
61 4 : deri.resize(natoms*natoms);
62 4 : reference_mat.resize(nresidues*nresidues);
63 4 : Pbc fake_pbc;
64 :
65 4 : calcMat(reference,fake_pbc,reference_mat,deri);
66 :
67 4 : }
68 :
69 1139266 : bool ERMSD::inPair(unsigned i, unsigned j) {
70 :
71 1139266 : if(pairs.size()==0) {
72 : return true;
73 : }
74 3982685 : for(unsigned idx=0; idx<pairs.size(); idx++) {
75 3414408 : if(pairs[idx].first == i && pairs[idx].second == j) {
76 : return true;
77 : }
78 3413730 : if(pairs[idx].second == i && pairs[idx].first == j) {
79 : return true;
80 : }
81 : }
82 : return false;
83 : }
84 :
85 226 : void ERMSD::calcMat(const std::vector<Vector> & positions,const Pbc& pbc, std::vector<Vector4d> &mat, std::vector<TensorGeneric<4,3> > &Gderi) {
86 :
87 : std::vector<Vector3d> pos;
88 226 : pos.resize(3*nresidues);
89 :
90 : std::vector<Tensor3d> deri;
91 226 : deri.resize(nresidues*9);
92 :
93 : std::vector<Vector> centers;
94 226 : centers.resize(nresidues);
95 :
96 : unsigned idx_deri = 0;
97 :
98 226 : Tensor da_dxa = (2./3.)*Tensor::identity();
99 226 : Tensor da_dxb = -(1./3.)*Tensor::identity();
100 226 : Tensor da_dxc = -(1./3.)*Tensor::identity();
101 :
102 226 : Tensor db_dxa = -(1./3.)*Tensor::identity();
103 226 : Tensor db_dxb = (2./3.)*Tensor::identity();
104 226 : Tensor db_dxc = -(1./3.)*Tensor::identity();
105 :
106 : // Form factors - should this be somewhere else?
107 :
108 : double w = 1./3.;
109 226 : Vector form_factor = Vector(2.0,2.0,1.0/0.3);
110 :
111 16272 : for(unsigned res_idx=0; res_idx<natoms/3; res_idx++) {
112 :
113 :
114 16046 : const unsigned at_idx = 3*res_idx;
115 : //center
116 64184 : for (unsigned j=0; j<3; j++) {
117 48138 : centers[res_idx] += w*positions[at_idx+j];
118 : }
119 :
120 16046 : Vector3d a = delta(centers[res_idx],positions[at_idx]);
121 16046 : Vector3d b = delta(centers[res_idx],positions[at_idx+1]);
122 16046 : Vector3d d = crossProduct(a,b);
123 16046 : double ianorm = 1./a.modulo();
124 16046 : double idnorm = 1./d.modulo();
125 :
126 : // X vector: COM-C2
127 16046 : pos[at_idx] = a*ianorm;
128 : // Z versor: C2 x (COM-C4/C6)
129 16046 : pos[at_idx+2] = d*idnorm;
130 : // Y versor: Z x Y
131 16046 : pos[at_idx+1] = crossProduct(pos[at_idx+2],pos[at_idx]);
132 :
133 : // Derivatives ////////
134 16046 : Tensor3d t1 = ianorm*(Tensor::identity()-extProduct(pos[at_idx],pos[at_idx]));
135 : // dv1/dxa
136 16046 : deri[idx_deri] = (2./3. )*t1;
137 : // dv1/dxb
138 16046 : deri[idx_deri+3] = -(1./3.)*t1;
139 : // dv1/dxc
140 16046 : deri[idx_deri+6] = -(1./3.)*t1;
141 :
142 16046 : Tensor dd_dxa = VcrossTensor(a,db_dxa) -VcrossTensor(b,da_dxa);
143 16046 : Tensor dd_dxb = VcrossTensor(a,db_dxb)-VcrossTensor(b,da_dxb);
144 16046 : Tensor dd_dxc = VcrossTensor(a,db_dxc)-VcrossTensor(b,da_dxc);
145 :
146 : // dv3/dxa
147 16046 : deri[idx_deri+2] = deriNorm(d,dd_dxa);
148 : // dv3/dxb
149 16046 : deri[idx_deri+5] = deriNorm(d,dd_dxb);
150 : // dv3/dxc
151 16046 : deri[idx_deri+8] = deriNorm(d,dd_dxc);
152 :
153 : // dv2/dxa = dv3/dxa cross v1 + v3 cross dv1/dxa
154 32092 : deri[idx_deri+1] = (VcrossTensor(deri[idx_deri+2],pos[at_idx]) + \
155 32092 : VcrossTensor(pos[at_idx+2],deri[idx_deri]));
156 : // dv2/dxb
157 32092 : deri[idx_deri+4] = (VcrossTensor(deri[idx_deri+5],pos[at_idx]) + \
158 32092 : VcrossTensor(pos[at_idx+2],deri[idx_deri+3]));
159 : // dv2/dxc
160 32092 : deri[idx_deri+7] = (VcrossTensor(deri[idx_deri+8],pos[at_idx]) + \
161 32092 : VcrossTensor(pos[at_idx+2],deri[idx_deri+6]));
162 :
163 16046 : idx_deri += 9;
164 : // End derivatives ///////
165 :
166 : }
167 :
168 :
169 : // Initialization (unnecessary?)
170 1139492 : for (unsigned i1=0; i1<nresidues*nresidues; i1++) {
171 5696330 : for (unsigned i2=0; i2<4; i2++) {
172 4557064 : mat[i1][i2] = 0.0;
173 : }
174 : }
175 :
176 226 : double maxdist = cutoff/form_factor[0];
177 226 : const double maxdist2 = maxdist*maxdist;
178 226 : double gamma = pi/cutoff;
179 : unsigned idx;
180 : unsigned idx1 = 0;
181 : // Calculate mat
182 16272 : for (unsigned i=0; i<nresidues; i++) {
183 1155312 : for (unsigned j=0; j<nresidues; j++) {
184 :
185 : // skip i==j
186 1139266 : if(inPair(i,j) and i != j) {
187 : //if(i!=j){
188 :
189 :
190 : // Calculate normal distance first
191 562966 : Vector diff = delta(centers[i],centers[j]);
192 562966 : if(diff.modulo2()<maxdist2) {
193 :
194 : // calculate r_tilde_ij
195 85382 : Vector3d rtilde;
196 341528 : for (unsigned k=0; k<3; k++) {
197 1024584 : for (unsigned l=0; l<3; l++) {
198 768438 : rtilde[l] += pos[3*i+l][k]*diff[k]*form_factor[l];
199 : }
200 : }
201 85382 : double rtilde_norm = rtilde.modulo();
202 :
203 85382 : double irnorm = 1./rtilde_norm;
204 :
205 : // ellipsoidal cutoff
206 85382 : if(rtilde_norm < cutoff) {
207 53822 : idx = i*nresidues + j;
208 :
209 :
210 : // fill 4d matrix
211 53822 : double dummy = std::sin(gamma*rtilde_norm)/(rtilde_norm*gamma);
212 53822 : mat[idx][0] = dummy*rtilde[0];
213 53822 : mat[idx][1] = dummy*rtilde[1];
214 53822 : mat[idx][2] = dummy*rtilde[2];
215 53822 : mat[idx][3] = (1.+ std::cos(gamma*rtilde_norm))/gamma;
216 :
217 : // Derivative (drtilde_dx)
218 53822 : std::array<Tensor3d,6> drtilde_dx;
219 53822 : unsigned pos_idx = 3*i;
220 53822 : unsigned deri_idx = 9*i;
221 215288 : for (unsigned at=0; at<3; at++) {
222 645864 : for (unsigned l=0; l<3; l++) {
223 484398 : Vector3d rvec = form_factor[l]*((pos[pos_idx+l])/3.);
224 484398 : Vector3d vvec = form_factor[l]*(matmul(deri[deri_idx+3*at+l],diff));
225 484398 : drtilde_dx[at].setRow(l,vvec-rvec);
226 484398 : drtilde_dx[at+3].setRow(l,rvec);
227 : }
228 : }
229 :
230 53822 : double dummy1 = (std::cos(gamma*rtilde_norm) - dummy);
231 :
232 53822 : idx1 = i*nresidues*6 + j*6;
233 :
234 376754 : for (unsigned l=0; l<6; l++) {
235 : //std::cout << i << " " << j << " " << idx1 << " " << idx1+l << "\n";
236 :
237 : // components 1,2,3
238 : // std::sin(gamma*|rtilde|)/gamma*|rtilde|*d_rtilde +
239 : // + ((d_rtilde*r_tilde/r_tilde^2) out r_tilde)*
240 : // (std::cos(gamma*|rtilde| - std::sin(gamma*|rtilde|)/gamma*|rtilde|))
241 322932 : Vector3d rdr = matmul(rtilde,drtilde_dx[l]);
242 322932 : Tensor tt = dummy*drtilde_dx[l] + (dummy1*irnorm*irnorm)*Tensor(rtilde,rdr);
243 1291728 : for (unsigned m=0; m<3; m++) {
244 : // Transpose here
245 : //dG_dx[l].setRow(m,tt.getRow(m));
246 968796 : Gderi[idx1+l].setRow(m,tt.getRow(m));
247 : }
248 : // component 4
249 : // - std::sin(gamma*|rtilde|)/|rtilde|*(r_tilde*d_rtilde)
250 : //dG_dx[l].setRow(3,-dummy*gamma*rdr);
251 322932 : Gderi[idx1+l].setRow(3,-dummy*gamma*rdr);
252 : }
253 :
254 :
255 :
256 :
257 : }
258 : }
259 : }
260 :
261 : }
262 : }
263 :
264 226 : }
265 :
266 :
267 222 : double ERMSD::calculate(const std::vector<Vector> & positions,const Pbc& pbc,\
268 : std::vector<Vector> &derivatives, Tensor& virial) {
269 :
270 :
271 : double ermsd=0.;
272 : std::vector<Vector4d> mat;
273 222 : mat.resize(nresidues*nresidues);
274 :
275 : std::vector<TensorGeneric<4,3> > Gderi;
276 222 : Gderi.resize(natoms*natoms);
277 :
278 222 : calcMat(positions,pbc,mat,Gderi);
279 :
280 : unsigned idx1 = 0;
281 15984 : for(unsigned i=0; i<nresidues; i++) {
282 1134864 : for(unsigned j=0; j<nresidues; j++) {
283 1119102 : unsigned ii = i*nresidues + j;
284 :
285 1119102 : Vector4d dd = delta(reference_mat[ii],mat[ii]);
286 1119102 : double val = dd.modulo2();
287 :
288 1119102 : if(val>0.0 && i!=j) {
289 :
290 256596 : for(unsigned k=0; k<3; k++) {
291 192447 : idx1 = i*nresidues*6 + j*6 + k;
292 :
293 192447 : derivatives[3*i+k] += matmul(dd,Gderi[idx1]);
294 192447 : derivatives[3*j+k] += matmul(dd,Gderi[idx1+3]);
295 : }
296 64149 : ermsd += val;
297 : }
298 : }
299 : }
300 :
301 222 : ermsd = std::sqrt(ermsd/nresidues);
302 222 : double iermsd = 1.0/(ermsd*nresidues);
303 47508 : for(unsigned i=0; i<natoms; ++i) {
304 47286 : derivatives[i] *= iermsd;
305 : }
306 :
307 222 : return ermsd;
308 : }
309 :
310 :
311 : }
|