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 <cmath>
35 : #include <iostream>
36 :
37 :
38 : namespace PLMD {
39 :
40 0 : void ERMSD::clear() {
41 : reference_mat.clear();
42 0 : }
43 :
44 : //void ERMSD::calcLcs(const vector<Vector> & positions, vector<Vector> &)
45 :
46 4 : void ERMSD::setReference(const std::vector<Vector> & reference, const std::vector<unsigned> & pairs_vec, double mycutoff) {
47 :
48 4 : natoms = reference.size();
49 4 : nresidues = natoms/3;
50 4 : unsigned npairs = pairs_vec.size()/2;
51 4 : pairs.resize(npairs);
52 16 : for(unsigned i=0; i<npairs; ++i) {
53 :
54 12 : pairs[i].first = pairs_vec[2*i];
55 12 : pairs[i].second = pairs_vec[2*i+1];
56 : }
57 :
58 4 : cutoff = mycutoff;
59 : std::vector<TensorGeneric<4,3> > deri;
60 4 : deri.resize(natoms*natoms);
61 4 : reference_mat.resize(nresidues*nresidues);
62 4 : Pbc fake_pbc;
63 :
64 4 : calcMat(reference,fake_pbc,reference_mat,deri);
65 :
66 8 : }
67 :
68 1139266 : bool ERMSD::inPair(unsigned i, unsigned j) {
69 :
70 1139266 : if(pairs.size()==0) return true;
71 3982685 : for(unsigned idx=0; idx<pairs.size(); idx++) {
72 3414408 : if(pairs[idx].first == i && pairs[idx].second == j) return true;
73 3413730 : if(pairs[idx].second == i && pairs[idx].first == j) return true;
74 : }
75 : return false;
76 : }
77 :
78 226 : void ERMSD::calcMat(const std::vector<Vector> & positions,const Pbc& pbc, std::vector<Vector4d> &mat, std::vector<TensorGeneric<4,3> > &Gderi) {
79 :
80 : std::vector<Vector3d> pos;
81 226 : pos.resize(3*nresidues);
82 :
83 : std::vector<Tensor3d> deri;
84 226 : deri.resize(nresidues*9);
85 :
86 : std::vector<Vector> centers;
87 226 : centers.resize(nresidues);
88 :
89 : unsigned idx_deri = 0;
90 :
91 226 : Tensor da_dxa = (2./3.)*Tensor::identity();
92 226 : Tensor da_dxb = -(1./3.)*Tensor::identity();
93 226 : Tensor da_dxc = -(1./3.)*Tensor::identity();
94 :
95 226 : Tensor db_dxa = -(1./3.)*Tensor::identity();
96 226 : Tensor db_dxb = (2./3.)*Tensor::identity();
97 226 : Tensor db_dxc = -(1./3.)*Tensor::identity();
98 :
99 : // Form factors - should this be somewhere else?
100 :
101 : double w = 1./3.;
102 226 : Vector form_factor = Vector(2.0,2.0,1.0/0.3);
103 :
104 16272 : for(unsigned res_idx=0; res_idx<natoms/3; res_idx++) {
105 :
106 :
107 16046 : const unsigned at_idx = 3*res_idx;
108 : //center
109 64184 : for (unsigned j=0; j<3; j++) {
110 48138 : centers[res_idx] += w*positions[at_idx+j];
111 : }
112 :
113 16046 : Vector3d a = delta(centers[res_idx],positions[at_idx]);
114 16046 : Vector3d b = delta(centers[res_idx],positions[at_idx+1]);
115 16046 : Vector3d d = crossProduct(a,b);
116 16046 : double ianorm = 1./a.modulo();
117 16046 : double idnorm = 1./d.modulo();
118 :
119 : // X vector: COM-C2
120 16046 : pos[at_idx] = a*ianorm;
121 : // Z versor: C2 x (COM-C4/C6)
122 16046 : pos[at_idx+2] = d*idnorm;
123 : // Y versor: Z x Y
124 16046 : pos[at_idx+1] = crossProduct(pos[at_idx+2],pos[at_idx]);
125 :
126 : // Derivatives ////////
127 16046 : Tensor3d t1 = ianorm*(Tensor::identity()-extProduct(pos[at_idx],pos[at_idx]));
128 : // dv1/dxa
129 16046 : deri[idx_deri] = (2./3. )*t1;
130 : // dv1/dxb
131 16046 : deri[idx_deri+3] = -(1./3.)*t1;
132 : // dv1/dxc
133 16046 : deri[idx_deri+6] = -(1./3.)*t1;
134 :
135 16046 : Tensor dd_dxa = VcrossTensor(a,db_dxa) -VcrossTensor(b,da_dxa);
136 16046 : Tensor dd_dxb = VcrossTensor(a,db_dxb)-VcrossTensor(b,da_dxb);
137 16046 : Tensor dd_dxc = VcrossTensor(a,db_dxc)-VcrossTensor(b,da_dxc);
138 :
139 : // dv3/dxa
140 16046 : deri[idx_deri+2] = deriNorm(d,dd_dxa);
141 : // dv3/dxb
142 16046 : deri[idx_deri+5] = deriNorm(d,dd_dxb);
143 : // dv3/dxc
144 16046 : deri[idx_deri+8] = deriNorm(d,dd_dxc);
145 :
146 : // dv2/dxa = dv3/dxa cross v1 + v3 cross dv1/dxa
147 16046 : deri[idx_deri+1] = (VcrossTensor(deri[idx_deri+2],pos[at_idx]) + \
148 32092 : VcrossTensor(pos[at_idx+2],deri[idx_deri]));
149 : // dv2/dxb
150 16046 : deri[idx_deri+4] = (VcrossTensor(deri[idx_deri+5],pos[at_idx]) + \
151 32092 : VcrossTensor(pos[at_idx+2],deri[idx_deri+3]));
152 : // dv2/dxc
153 16046 : deri[idx_deri+7] = (VcrossTensor(deri[idx_deri+8],pos[at_idx]) + \
154 32092 : VcrossTensor(pos[at_idx+2],deri[idx_deri+6]));
155 :
156 16046 : idx_deri += 9;
157 : // End derivatives ///////
158 :
159 : }
160 :
161 :
162 : // Initialization (unnecessary?)
163 1139492 : for (unsigned i1=0; i1<nresidues*nresidues; i1++) {
164 5696330 : for (unsigned i2=0; i2<4; i2++) {
165 4557064 : mat[i1][i2] = 0.0;
166 : }
167 : }
168 :
169 226 : double maxdist = cutoff/form_factor[0];
170 226 : double gamma = pi/cutoff;
171 : unsigned idx;
172 : unsigned idx1 = 0;
173 : // Calculate mat
174 16272 : for (unsigned i=0; i<nresidues; i++) {
175 1155312 : for (unsigned j=0; j<nresidues; j++) {
176 :
177 : // skip i==j
178 1139266 : if(inPair(i,j) and i != j) {
179 : //if(i!=j){
180 :
181 :
182 : // Calculate normal distance first
183 562966 : Vector diff = delta(centers[i],centers[j]);
184 562966 : double d1 = diff.modulo();
185 562966 : if(d1<maxdist) {
186 :
187 : // calculate r_tilde_ij
188 85382 : Vector3d rtilde;
189 341528 : for (unsigned k=0; k<3; k++) {
190 1024584 : for (unsigned l=0; l<3; l++) {
191 768438 : rtilde[l] += pos[3*i+l][k]*diff[k]*form_factor[l];
192 : }
193 : }
194 85382 : double rtilde_norm = rtilde.modulo();
195 :
196 85382 : double irnorm = 1./rtilde_norm;
197 :
198 : // ellipsoidal cutoff
199 85382 : if(rtilde_norm < cutoff) {
200 53822 : idx = i*nresidues + j;
201 :
202 :
203 : // fill 4d matrix
204 53822 : double dummy = std::sin(gamma*rtilde_norm)/(rtilde_norm*gamma);
205 53822 : mat[idx][0] = dummy*rtilde[0];
206 53822 : mat[idx][1] = dummy*rtilde[1];
207 53822 : mat[idx][2] = dummy*rtilde[2];
208 53822 : mat[idx][3] = (1.+ std::cos(gamma*rtilde_norm))/gamma;
209 :
210 : // Derivative (drtilde_dx)
211 : std::vector<Tensor3d> drtilde_dx;
212 53822 : drtilde_dx.resize(6);
213 53822 : unsigned pos_idx = 3*i;
214 53822 : unsigned deri_idx = 9*i;
215 215288 : for (unsigned at=0; at<3; at++) {
216 645864 : for (unsigned l=0; l<3; l++) {
217 484398 : Vector3d rvec = form_factor[l]*((pos[pos_idx+l])/3.);
218 484398 : Vector3d vvec = form_factor[l]*(matmul(deri[deri_idx+3*at+l],diff));
219 484398 : drtilde_dx[at].setRow(l,vvec-rvec);
220 484398 : drtilde_dx[at+3].setRow(l,rvec);
221 : }
222 : }
223 :
224 53822 : double dummy1 = (std::cos(gamma*rtilde_norm) - dummy);
225 :
226 53822 : idx1 = i*nresidues*6 + j*6;
227 :
228 376754 : for (unsigned l=0; l<6; l++) {
229 : //std::cout << i << " " << j << " " << idx1 << " " << idx1+l << "\n";
230 :
231 : // components 1,2,3
232 : // std::sin(gamma*|rtilde|)/gamma*|rtilde|*d_rtilde +
233 : // + ((d_rtilde*r_tilde/r_tilde^2) out r_tilde)*
234 : // (std::cos(gamma*|rtilde| - std::sin(gamma*|rtilde|)/gamma*|rtilde|))
235 322932 : Vector3d rdr = matmul(rtilde,drtilde_dx[l]);
236 322932 : Tensor tt = dummy*drtilde_dx[l] + (dummy1*irnorm*irnorm)*Tensor(rtilde,rdr);
237 1291728 : for (unsigned m=0; m<3; m++) {
238 : // Transpose here
239 : //dG_dx[l].setRow(m,tt.getRow(m));
240 968796 : Gderi[idx1+l].setRow(m,tt.getRow(m));
241 : }
242 : // component 4
243 : // - std::sin(gamma*|rtilde|)/|rtilde|*(r_tilde*d_rtilde)
244 : //dG_dx[l].setRow(3,-dummy*gamma*rdr);
245 322932 : Gderi[idx1+l].setRow(3,-dummy*gamma*rdr);
246 : }
247 :
248 :
249 :
250 :
251 : }
252 : }
253 : }
254 :
255 : }
256 : }
257 :
258 226 : }
259 :
260 :
261 222 : double ERMSD::calculate(const std::vector<Vector> & positions,const Pbc& pbc,\
262 : std::vector<Vector> &derivatives, Tensor& virial) {
263 :
264 :
265 : double ermsd=0.;
266 : std::vector<Vector4d> mat;
267 222 : mat.resize(nresidues*nresidues);
268 :
269 : std::vector<TensorGeneric<4,3> > Gderi;
270 222 : Gderi.resize(natoms*natoms);
271 :
272 222 : calcMat(positions,pbc,mat,Gderi);
273 :
274 : unsigned idx1 = 0;
275 15984 : for(unsigned i=0; i<nresidues; i++) {
276 1134864 : for(unsigned j=0; j<nresidues; j++) {
277 1119102 : unsigned ii = i*nresidues + j;
278 :
279 1119102 : Vector4d dd = delta(reference_mat[ii],mat[ii]);
280 1119102 : double val = dd.modulo2();
281 :
282 1119102 : if(val>0.0 && i!=j) {
283 :
284 256596 : for(unsigned k=0; k<3; k++) {
285 192447 : idx1 = i*nresidues*6 + j*6 + k;
286 :
287 192447 : derivatives[3*i+k] += matmul(dd,Gderi[idx1]);
288 192447 : derivatives[3*j+k] += matmul(dd,Gderi[idx1+3]);
289 : }
290 64149 : ermsd += val;
291 : }
292 : }
293 : }
294 :
295 222 : ermsd = std::sqrt(ermsd/nresidues);
296 222 : double iermsd = 1.0/(ermsd*nresidues);
297 47508 : for(unsigned i=0; i<natoms; ++i) {derivatives[i] *= iermsd;}
298 :
299 222 : return ermsd;
300 : }
301 :
302 :
303 : }
|