Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-2019 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 : #include "RMSD.h"
23 : #include "PDB.h"
24 : #include "Log.h"
25 : #include "Exception.h"
26 : #include <cmath>
27 : #include <iostream>
28 : #include "Tools.h"
29 : using namespace std;
30 : namespace PLMD {
31 :
32 94576 : RMSD::RMSD() : alignmentMethod(SIMPLE),reference_center_is_calculated(false),reference_center_is_removed(false),positions_center_is_calculated(false),positions_center_is_removed(false) {}
33 :
34 : ///
35 : /// general method to set all the rmsd property at once by using a pdb where occupancy column sets the weights for the atoms involved in the
36 : /// alignment and beta sets the weight that are used for calculating the displacement.
37 : ///
38 1057 : void RMSD::set(const PDB&pdb, const string & mytype, bool remove_center, bool normalize_weights ) {
39 :
40 1057 : set(pdb.getOccupancy(),pdb.getBeta(),pdb.getPositions(),mytype,remove_center,normalize_weights);
41 :
42 1057 : }
43 2056 : void RMSD::set(const std::vector<double> & align, const std::vector<double> & displace, const std::vector<Vector> & reference, const string & mytype, bool remove_center, bool normalize_weights ) {
44 :
45 2056 : setReference(reference); // this by default remove the com and assumes uniform weights
46 2056 : setAlign(align, normalize_weights, remove_center); // this recalculates the com with weights. If remove_center=false then it restore the center back
47 2056 : setDisplace(displace, normalize_weights); // this is does not affect any calculation of the weights
48 2056 : setType(mytype);
49 :
50 2056 : }
51 :
52 47248 : void RMSD::setType(const string & mytype) {
53 :
54 47248 : alignmentMethod=SIMPLE; // initialize with the simplest case: no rotation
55 47248 : if (mytype=="SIMPLE") {
56 0 : alignmentMethod=SIMPLE;
57 : }
58 47248 : else if (mytype=="OPTIMAL") {
59 47248 : alignmentMethod=OPTIMAL;
60 : }
61 0 : else if (mytype=="OPTIMAL-FAST") {
62 0 : alignmentMethod=OPTIMAL_FAST;
63 : }
64 0 : else plumed_merror("unknown RMSD type" + mytype);
65 :
66 47248 : }
67 :
68 1010 : void RMSD::clear() {
69 : reference.clear();
70 1010 : reference_center.zero();
71 1010 : reference_center_is_calculated=false;
72 1010 : reference_center_is_removed=false;
73 : align.clear();
74 : displace.clear();
75 1010 : positions_center.zero();
76 1010 : positions_center_is_calculated=false;
77 1010 : positions_center_is_removed=false;
78 1010 : }
79 :
80 4 : string RMSD::getMethod() {
81 : string mystring;
82 4 : switch(alignmentMethod) {
83 0 : case SIMPLE: mystring.assign("SIMPLE"); break;
84 4 : case OPTIMAL: mystring.assign("OPTIMAL"); break;
85 0 : case OPTIMAL_FAST: mystring.assign("OPTIMAL-FAST"); break;
86 : }
87 4 : return mystring;
88 : }
89 : ///
90 : /// this calculates the center of mass for the reference and removes it from the reference itself
91 : /// considering uniform weights for alignment
92 : ///
93 47264 : void RMSD::setReference(const vector<Vector> & reference) {
94 47264 : unsigned n=reference.size();
95 47264 : this->reference=reference;
96 47264 : plumed_massert(align.empty(),"you should first clear() an RMSD object, then set a new reference");
97 47264 : plumed_massert(displace.empty(),"you should first clear() an RMSD object, then set a new reference");
98 47264 : align.resize(n,1.0/n);
99 47264 : displace.resize(n,1.0/n);
100 1913936 : for(unsigned i=0; i<n; i++) reference_center+=this->reference[i]*align[i];
101 : #pragma omp simd
102 1244448 : for(unsigned i=0; i<n; i++) this->reference[i]-=reference_center;
103 47264 : reference_center_is_calculated=true;
104 47264 : reference_center_is_removed=true;
105 47264 : }
106 45192 : std::vector<Vector> RMSD::getReference() {
107 45192 : return reference;
108 : }
109 : ///
110 : /// the alignment weights are here normalized to 1 and the center of the reference is removed accordingly
111 : ///
112 2056 : void RMSD::setAlign(const vector<double> & align, bool normalize_weights, bool remove_center) {
113 2056 : unsigned n=reference.size();
114 2056 : plumed_massert(this->align.size()==align.size(),"mismatch in dimension of align/displace arrays");
115 2056 : this->align=align;
116 2056 : if(normalize_weights) {
117 : double w=0.0;
118 4104 : #pragma omp simd reduction(+:w)
119 69000 : for(unsigned i=0; i<n; i++) w+=this->align[i];
120 2052 : plumed_massert(w>epsilon,"It looks like weights used for alignment are zero. Check your reference PDB file.");
121 2052 : double inv=1.0/w;
122 : #pragma omp simd
123 69000 : for(unsigned i=0; i<n; i++) this->align[i]*=inv;
124 : }
125 : // recalculate the center anyway
126 : // just remove the center if that is asked
127 : // if the center was removed before, then add it and store the new one
128 2056 : if(reference_center_is_removed) {
129 2056 : plumed_massert(reference_center_is_calculated," seems that the reference center has been removed but not calculated and stored!");
130 2056 : addCenter(reference,reference_center);
131 : }
132 2056 : reference_center=calculateCenter(reference,this->align);
133 2056 : reference_center_is_calculated=true;
134 2056 : if(remove_center) {
135 2052 : removeCenter(reference,reference_center);
136 2052 : reference_center_is_removed=true;
137 : } else {
138 4 : reference_center_is_removed=false;
139 : }
140 2056 : }
141 0 : std::vector<double> RMSD::getAlign() {
142 0 : return align;
143 : }
144 : ///
145 : /// here the weigth for normalized weighths are normalized and set
146 : ///
147 2056 : void RMSD::setDisplace(const vector<double> & displace, bool normalize_weights) {
148 2056 : unsigned n=reference.size();
149 2056 : plumed_massert(this->displace.size()==displace.size(),"mismatch in dimension of align/displace arrays");
150 2056 : this->displace=displace;
151 : double w=0.0;
152 4112 : #pragma omp simd reduction(+:w)
153 69040 : for(unsigned i=0; i<n; i++) w+=this->displace[i];
154 2056 : plumed_massert(w>epsilon,"It looks like weights used for displacement are zero. Check your reference PDB file.");
155 2056 : double inv=1.0/w;
156 2056 : if(normalize_weights) {
157 : #pragma omp simd
158 69000 : for(unsigned i=0; i<n; i++) this->displace[i]*=inv;
159 : }
160 2056 : }
161 0 : std::vector<double> RMSD::getDisplace() {
162 0 : return displace;
163 : }
164 : ///
165 : /// This is the main workhorse for rmsd that decides to use specific optimal alignment versions
166 : ///
167 330337 : double RMSD::calculate(const std::vector<Vector> & positions,std::vector<Vector> &derivatives, bool squared)const {
168 :
169 : double ret=0.;
170 :
171 330337 : switch(alignmentMethod) {
172 : case SIMPLE : {
173 : // do a simple alignment without rotation
174 0 : std::vector<Vector> displacement( derivatives.size() );
175 0 : ret=simpleAlignment(align,displace,positions,reference,derivatives,displacement,squared);
176 : break;
177 0 : } case OPTIMAL_FAST : {
178 : // this is calling the fastest option:
179 0 : if(align==displace) ret=optimalAlignment<false,true>(align,displace,positions,reference,derivatives,squared);
180 0 : else ret=optimalAlignment<false,false>(align,displace,positions,reference,derivatives,squared);
181 : break;
182 :
183 330337 : } case OPTIMAL : {
184 : // this is the fast routine but in the "safe" mode, which gives less numerical error:
185 330337 : if(align==displace) ret=optimalAlignment<true,true>(align,displace,positions,reference,derivatives,squared);
186 1 : else ret=optimalAlignment<true,false>(align,displace,positions,reference,derivatives,squared);
187 : break;
188 : }
189 : }
190 :
191 330337 : return ret;
192 :
193 : }
194 :
195 :
196 : /// convenience method for calculating the standard derivatives and the derivative of the rmsd respect to the reference position
197 1 : double RMSD::calc_DDistDRef( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, const bool squared ) {
198 : double ret=0.;
199 1 : switch(alignmentMethod) {
200 0 : case SIMPLE:
201 0 : plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
202 : break;
203 0 : case OPTIMAL_FAST:
204 0 : if(align==displace) ret=optimalAlignment_DDistDRef<false,true>(align,displace,positions,reference,derivatives,DDistDRef, squared);
205 0 : else ret=optimalAlignment_DDistDRef<false,false>(align,displace,positions,reference,derivatives,DDistDRef,squared);
206 : break;
207 1 : case OPTIMAL:
208 1 : if(align==displace) ret=optimalAlignment_DDistDRef<true,true>(align,displace,positions,reference,derivatives,DDistDRef,squared);
209 1 : else ret=optimalAlignment_DDistDRef<true,false>(align,displace,positions,reference,derivatives,DDistDRef,squared);
210 : break;
211 : }
212 1 : return ret;
213 :
214 : }
215 :
216 : /// convenience method for calculating the standard derivatives and the derivative of the rmsd respect to the reference position without the matrix contribution
217 : /// as required by SOMA
218 0 : double RMSD::calc_SOMA( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, const bool squared ) {
219 : double ret=0.;
220 0 : switch(alignmentMethod) {
221 0 : case SIMPLE:
222 0 : plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
223 : break;
224 0 : case OPTIMAL_FAST:
225 0 : if(align==displace) ret=optimalAlignment_SOMA<false,true>(align,displace,positions,reference,derivatives,DDistDRef, squared);
226 0 : else ret=optimalAlignment_SOMA<false,false>(align,displace,positions,reference,derivatives,DDistDRef,squared);
227 : break;
228 0 : case OPTIMAL:
229 0 : if(align==displace) ret=optimalAlignment_SOMA<true,true>(align,displace,positions,reference,derivatives,DDistDRef,squared);
230 0 : else ret=optimalAlignment_SOMA<true,false>(align,displace,positions,reference,derivatives,DDistDRef,squared);
231 : break;
232 : }
233 0 : return ret;
234 :
235 : }
236 :
237 0 : double RMSD::calc_DDistDRef_Rot_DRotDPos( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, Tensor & Rot, Matrix<std::vector<Vector> > &DRotDPos, const bool squared ) {
238 : double ret=0.;
239 0 : switch(alignmentMethod) {
240 0 : case SIMPLE:
241 0 : plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
242 : break;
243 0 : case OPTIMAL_FAST:
244 0 : if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos<false,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared);
245 0 : else ret=optimalAlignment_DDistDRef_Rot_DRotDPos<false,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared);
246 : break;
247 0 : case OPTIMAL:
248 0 : if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos<true,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared);
249 0 : else ret=optimalAlignment_DDistDRef_Rot_DRotDPos<true,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, squared);
250 : break;
251 : }
252 0 : return ret;
253 : }
254 :
255 0 : double RMSD::calc_DDistDRef_Rot_DRotDPos_DRotDRef( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, std::vector<Vector>& DDistDRef, Tensor & Rot, Matrix<std::vector<Vector> > &DRotDPos, Matrix<std::vector<Vector> > &DRotDRef, const bool squared ) {
256 : double ret=0.;
257 0 : switch(alignmentMethod) {
258 0 : case SIMPLE:
259 0 : plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
260 : break;
261 0 : case OPTIMAL_FAST:
262 0 : if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<false,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared);
263 0 : else ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<false,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared);
264 : break;
265 0 : case OPTIMAL:
266 0 : if(align==displace) ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<true,true>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared);
267 0 : else ret=optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef<true,false>(align,displace,positions,reference,derivatives,DDistDRef, Rot, DRotDPos, DRotDRef, squared);
268 : break;
269 : }
270 0 : return ret;
271 : }
272 :
273 1092 : double RMSD::calc_Rot_DRotDRr01( const std::vector<Vector>& positions, Tensor & Rotation, std::array<std::array<Tensor,3>,3> & DRotDRr01, const bool squared) {
274 : double ret=0.;
275 1092 : switch(alignmentMethod) {
276 0 : case SIMPLE:
277 0 : plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
278 : break;
279 0 : case OPTIMAL_FAST:
280 0 : if(align==displace) ret=optimalAlignment_Rot_DRotDRr01<false,true>(align,displace,positions,reference, Rotation, DRotDRr01, squared);
281 0 : else ret=optimalAlignment_Rot_DRotDRr01<false,false>(align,displace,positions,reference, Rotation, DRotDRr01, squared);
282 : break;
283 1092 : case OPTIMAL:
284 1092 : if(align==displace) ret=optimalAlignment_Rot_DRotDRr01<true,true>(align,displace,positions,reference, Rotation, DRotDRr01, squared);
285 0 : else ret=optimalAlignment_Rot_DRotDRr01<true,false>(align,displace,positions,reference, Rotation, DRotDRr01, squared);
286 : break;
287 : }
288 1092 : return ret;
289 : }
290 :
291 672 : double RMSD::calc_Rot( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, Tensor & Rotation, const bool squared) {
292 : double ret=0.;
293 672 : switch(alignmentMethod) {
294 0 : case SIMPLE:
295 0 : plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
296 : break;
297 0 : case OPTIMAL_FAST:
298 0 : if(align==displace) ret=optimalAlignment_Rot<false,true>(align,displace,positions,reference,derivatives, Rotation, squared);
299 0 : else ret=optimalAlignment_Rot<false,false>(align,displace,positions,reference,derivatives, Rotation, squared);
300 : break;
301 672 : case OPTIMAL:
302 672 : if(align==displace) ret=optimalAlignment_Rot<true,true>(align,displace,positions,reference,derivatives, Rotation, squared);
303 0 : else ret=optimalAlignment_Rot<true,false>(align,displace,positions,reference,derivatives, Rotation, squared);
304 : break;
305 : }
306 672 : return ret;
307 : }
308 :
309 45192 : double RMSD::calculateWithCloseStructure( const std::vector<Vector>& positions, std::vector<Vector> &derivatives, Tensor & rotationPosClose, Tensor & rotationRefClose, std::array<std::array<Tensor,3>,3> & drotationPosCloseDrr01, const bool squared) {
310 : double ret=0.;
311 45192 : switch(alignmentMethod) {
312 0 : case SIMPLE:
313 0 : plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
314 : break;
315 0 : case OPTIMAL_FAST:
316 0 : if(align==displace) ret=optimalAlignmentWithCloseStructure<false,true>(align,displace,positions,reference,derivatives, rotationPosClose, rotationRefClose, drotationPosCloseDrr01, squared);
317 0 : else ret=optimalAlignmentWithCloseStructure<false,false>(align,displace,positions,reference,derivatives, rotationPosClose, rotationRefClose, drotationPosCloseDrr01, squared);
318 : break;
319 45192 : case OPTIMAL:
320 45192 : if(align==displace) ret=optimalAlignmentWithCloseStructure<true,true>(align,displace,positions,reference,derivatives, rotationPosClose, rotationRefClose, drotationPosCloseDrr01, squared);
321 0 : else ret=optimalAlignmentWithCloseStructure<true,false>(align,displace,positions,reference,derivatives, rotationPosClose, rotationRefClose, drotationPosCloseDrr01, squared);
322 : break;
323 : }
324 45192 : return ret;
325 : }
326 :
327 4441 : double RMSD::calc_PCAelements( const std::vector<Vector>& positions, std::vector<Vector> &DDistDPos, Tensor & Rotation, Matrix<std::vector<Vector> > & DRotDPos,std::vector<Vector> & alignedpositions, std::vector<Vector> & centeredpositions, std::vector<Vector> ¢eredreference, const bool& squared ) const {
328 : double ret=0.;
329 4441 : switch(alignmentMethod) {
330 0 : case SIMPLE:
331 0 : plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
332 : break;
333 0 : case OPTIMAL_FAST:
334 0 : if(align==displace) ret=optimalAlignment_PCA<false,true>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared);
335 0 : else ret=optimalAlignment_PCA<false,false>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared);
336 : break;
337 4441 : case OPTIMAL:
338 4441 : if(align==displace) ret=optimalAlignment_PCA<true,true>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared);
339 0 : else ret=optimalAlignment_PCA<true,false>(align,displace,positions,reference, alignedpositions, centeredpositions,centeredreference,Rotation,DDistDPos,DRotDPos,squared);
340 : break;
341 : }
342 4441 : return ret;
343 : }
344 :
345 :
346 48 : double RMSD::calc_FitElements( const std::vector<Vector>& positions, Tensor & Rotation, Matrix<std::vector<Vector> > & DRotDPos, std::vector<Vector> & centeredpositions, Vector ¢er_positions, const bool& squared ) {
347 : double ret=0.;
348 48 : switch(alignmentMethod) {
349 0 : case SIMPLE:
350 0 : plumed_merror("derivative of the refreence frame not implemented for SIMPLE alignmentMethod \n");
351 : break;
352 0 : case OPTIMAL_FAST:
353 0 : if(align==displace)ret=optimalAlignment_Fit<false,true>(align,displace,positions,reference, Rotation,DRotDPos,centeredpositions,center_positions,squared);
354 0 : else ret=optimalAlignment_Fit<false,false>(align,displace,positions,reference, Rotation,DRotDPos,centeredpositions,center_positions,squared);
355 : break;
356 48 : case OPTIMAL:
357 48 : if(align==displace)ret=optimalAlignment_Fit<true,true>(align,displace,positions,reference,Rotation,DRotDPos,centeredpositions,center_positions,squared);
358 48 : else ret=optimalAlignment_Fit<true,false>(align,displace,positions,reference,Rotation,DRotDPos,centeredpositions,center_positions,squared);
359 : break;
360 : }
361 48 : return ret;
362 : }
363 :
364 :
365 :
366 :
367 :
368 :
369 149 : double RMSD::simpleAlignment(const std::vector<double> & align,
370 : const std::vector<double> & displace,
371 : const std::vector<Vector> & positions,
372 : const std::vector<Vector> & reference,
373 : std::vector<Vector> & derivatives,
374 : std::vector<Vector> & displacement,
375 : bool squared)const {
376 :
377 : double dist(0);
378 149 : unsigned n=reference.size();
379 :
380 149 : Vector apositions;
381 149 : Vector areference;
382 149 : Vector dpositions;
383 149 : Vector dreference;
384 :
385 4693 : for(unsigned i=0; i<n; i++) {
386 4544 : double aw=align[i];
387 2272 : double dw=displace[i];
388 2272 : apositions+=positions[i]*aw;
389 2272 : areference+=reference[i]*aw;
390 2272 : dpositions+=positions[i]*dw;
391 2272 : dreference+=reference[i]*dw;
392 : }
393 :
394 149 : Vector shift=((apositions-areference)-(dpositions-dreference));
395 4693 : for(unsigned i=0; i<n; i++) {
396 9088 : displacement[i]=(positions[i]-apositions)-(reference[i]-areference);
397 4544 : dist+=displace[i]*displacement[i].modulo2();
398 6816 : derivatives[i]=2*(displace[i]*displacement[i]+align[i]*shift);
399 : }
400 :
401 149 : if(!squared) {
402 : // sqrt
403 106 : dist=sqrt(dist);
404 : ///// sqrt on derivatives
405 4192 : for(unsigned i=0; i<n; i++) {derivatives[i]*=(0.5/dist);}
406 : }
407 149 : return dist;
408 : }
409 :
410 : // this below enable the standard case for rmsd where the rmsd is calculated and the derivative of rmsd respect to positions is retrieved
411 : // additionally this assumes that the com of the reference is already subtracted.
412 : #define OLDRMSD
413 : #ifdef OLDRMSD
414 : // notice that in the current implementation the safe argument only makes sense for
415 : // align==displace
416 : template <bool safe,bool alEqDis>
417 546477 : double RMSD::optimalAlignment(const std::vector<double> & align,
418 : const std::vector<double> & displace,
419 : const std::vector<Vector> & positions,
420 : const std::vector<Vector> & reference,
421 : std::vector<Vector> & derivatives, bool squared)const {
422 : double dist(0);
423 546477 : const unsigned n=reference.size();
424 : // This is the trace of positions*positions + reference*reference
425 : double rr00(0);
426 : double rr11(0);
427 : // This is positions*reference
428 546477 : Tensor rr01;
429 :
430 546477 : derivatives.resize(n);
431 :
432 546477 : Vector cpositions;
433 :
434 : // first expensive loop: compute centers
435 44117285 : for(unsigned iat=0; iat<n; iat++) {
436 43570808 : double w=align[iat];
437 21785404 : cpositions+=positions[iat]*w;
438 : }
439 :
440 : // second expensive loop: compute second moments wrt centers
441 44117285 : for(unsigned iat=0; iat<n; iat++) {
442 43570808 : double w=align[iat];
443 43570808 : rr00+=dotProduct(positions[iat]-cpositions,positions[iat]-cpositions)*w;
444 21783228 : rr11+=dotProduct(reference[iat],reference[iat])*w;
445 21785404 : rr01+=Tensor(positions[iat]-cpositions,reference[iat])*w;
446 : }
447 :
448 : Matrix<double> m=Matrix<double>(4,4);
449 546477 : m[0][0]=2.0*(-rr01[0][0]-rr01[1][1]-rr01[2][2]);
450 546477 : m[1][1]=2.0*(-rr01[0][0]+rr01[1][1]+rr01[2][2]);
451 546477 : m[2][2]=2.0*(+rr01[0][0]-rr01[1][1]+rr01[2][2]);
452 546477 : m[3][3]=2.0*(+rr01[0][0]+rr01[1][1]-rr01[2][2]);
453 546477 : m[0][1]=2.0*(-rr01[1][2]+rr01[2][1]);
454 546477 : m[0][2]=2.0*(+rr01[0][2]-rr01[2][0]);
455 546477 : m[0][3]=2.0*(-rr01[0][1]+rr01[1][0]);
456 546477 : m[1][2]=2.0*(-rr01[0][1]-rr01[1][0]);
457 546477 : m[1][3]=2.0*(-rr01[0][2]-rr01[2][0]);
458 546477 : m[2][3]=2.0*(-rr01[1][2]-rr01[2][1]);
459 546477 : m[1][0] = m[0][1];
460 546477 : m[2][0] = m[0][2];
461 546477 : m[2][1] = m[1][2];
462 546477 : m[3][0] = m[0][3];
463 546477 : m[3][1] = m[1][3];
464 546477 : m[3][2] = m[2][3];
465 :
466 2732385 : Tensor dm_drr01[4][4];
467 : if(!alEqDis) {
468 114 : dm_drr01[0][0] = 2.0*Tensor(-1.0, 0.0, 0.0, 0.0,-1.0, 0.0, 0.0, 0.0,-1.0);
469 114 : dm_drr01[1][1] = 2.0*Tensor(-1.0, 0.0, 0.0, 0.0,+1.0, 0.0, 0.0, 0.0,+1.0);
470 114 : dm_drr01[2][2] = 2.0*Tensor(+1.0, 0.0, 0.0, 0.0,-1.0, 0.0, 0.0, 0.0,+1.0);
471 114 : dm_drr01[3][3] = 2.0*Tensor(+1.0, 0.0, 0.0, 0.0,+1.0, 0.0, 0.0, 0.0,-1.0);
472 114 : dm_drr01[0][1] = 2.0*Tensor( 0.0, 0.0, 0.0, 0.0, 0.0,-1.0, 0.0,+1.0, 0.0);
473 114 : dm_drr01[0][2] = 2.0*Tensor( 0.0, 0.0,+1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0);
474 114 : dm_drr01[0][3] = 2.0*Tensor( 0.0,-1.0, 0.0, +1.0, 0.0, 0.0, 0.0, 0.0, 0.0);
475 114 : dm_drr01[1][2] = 2.0*Tensor( 0.0,-1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0);
476 114 : dm_drr01[1][3] = 2.0*Tensor( 0.0, 0.0,-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0);
477 114 : dm_drr01[2][3] = 2.0*Tensor( 0.0, 0.0, 0.0, 0.0, 0.0,-1.0, 0.0,-1.0, 0.0);
478 114 : dm_drr01[1][0] = dm_drr01[0][1];
479 114 : dm_drr01[2][0] = dm_drr01[0][2];
480 114 : dm_drr01[2][1] = dm_drr01[1][2];
481 114 : dm_drr01[3][0] = dm_drr01[0][3];
482 114 : dm_drr01[3][1] = dm_drr01[1][3];
483 114 : dm_drr01[3][2] = dm_drr01[2][3];
484 : }
485 :
486 : vector<double> eigenvals;
487 : Matrix<double> eigenvecs;
488 546477 : int diagerror=diagMat(m, eigenvals, eigenvecs );
489 :
490 546477 : if (diagerror!=0) {
491 : string sdiagerror;
492 0 : Tools::convert(diagerror,sdiagerror);
493 0 : string msg="DIAGONALIZATION FAILED WITH ERROR CODE "+sdiagerror;
494 0 : plumed_merror(msg);
495 : }
496 :
497 546363 : dist=eigenvals[0]+rr00+rr11;
498 :
499 : Matrix<double> ddist_dm(4,4);
500 :
501 1092954 : Vector4d q(eigenvecs[0][0],eigenvecs[0][1],eigenvecs[0][2],eigenvecs[0][3]);
502 :
503 2732385 : Tensor dq_drr01[4];
504 : if(!alEqDis) {
505 : double dq_dm[4][4][4];
506 7866 : for(unsigned i=0; i<4; i++) for(unsigned j=0; j<4; j++) for(unsigned k=0; k<4; k++) {
507 : double tmp=0.0;
508 : // perturbation theory for matrix m
509 72960 : for(unsigned l=1; l<4; l++) tmp+=eigenvecs[l][j]*eigenvecs[l][i]/(eigenvals[0]-eigenvals[l])*eigenvecs[0][k];
510 7296 : dq_dm[i][j][k]=tmp;
511 : }
512 : // propagation to _drr01
513 1026 : for(unsigned i=0; i<4; i++) {
514 456 : Tensor tmp;
515 9576 : for(unsigned j=0; j<4; j++) for(unsigned k=0; k<4; k++) {
516 7296 : tmp+=dq_dm[i][j][k]*dm_drr01[j][k];
517 : }
518 456 : dq_drr01[i]=tmp;
519 : }
520 : }
521 :
522 : // This is the rotation matrix that brings reference to positions
523 : // i.e. matmul(rotation,reference[iat])+shift is fitted to positions[iat]
524 :
525 546477 : Tensor rotation;
526 546477 : rotation[0][0]=q[0]*q[0]+q[1]*q[1]-q[2]*q[2]-q[3]*q[3];
527 546477 : rotation[1][1]=q[0]*q[0]-q[1]*q[1]+q[2]*q[2]-q[3]*q[3];
528 546477 : rotation[2][2]=q[0]*q[0]-q[1]*q[1]-q[2]*q[2]+q[3]*q[3];
529 546477 : rotation[0][1]=2*(+q[0]*q[3]+q[1]*q[2]);
530 546477 : rotation[0][2]=2*(-q[0]*q[2]+q[1]*q[3]);
531 546477 : rotation[1][2]=2*(+q[0]*q[1]+q[2]*q[3]);
532 546477 : rotation[1][0]=2*(-q[0]*q[3]+q[1]*q[2]);
533 546477 : rotation[2][0]=2*(+q[0]*q[2]+q[1]*q[3]);
534 546477 : rotation[2][1]=2*(-q[0]*q[1]+q[2]*q[3]);
535 :
536 :
537 546477 : std::array<std::array<Tensor,3>,3> drotation_drr01;
538 : if(!alEqDis) {
539 114 : drotation_drr01[0][0]=2*q[0]*dq_drr01[0]+2*q[1]*dq_drr01[1]-2*q[2]*dq_drr01[2]-2*q[3]*dq_drr01[3];
540 114 : drotation_drr01[1][1]=2*q[0]*dq_drr01[0]-2*q[1]*dq_drr01[1]+2*q[2]*dq_drr01[2]-2*q[3]*dq_drr01[3];
541 114 : drotation_drr01[2][2]=2*q[0]*dq_drr01[0]-2*q[1]*dq_drr01[1]-2*q[2]*dq_drr01[2]+2*q[3]*dq_drr01[3];
542 114 : drotation_drr01[0][1]=2*(+(q[0]*dq_drr01[3]+dq_drr01[0]*q[3])+(q[1]*dq_drr01[2]+dq_drr01[1]*q[2]));
543 114 : drotation_drr01[0][2]=2*(-(q[0]*dq_drr01[2]+dq_drr01[0]*q[2])+(q[1]*dq_drr01[3]+dq_drr01[1]*q[3]));
544 114 : drotation_drr01[1][2]=2*(+(q[0]*dq_drr01[1]+dq_drr01[0]*q[1])+(q[2]*dq_drr01[3]+dq_drr01[2]*q[3]));
545 114 : drotation_drr01[1][0]=2*(-(q[0]*dq_drr01[3]+dq_drr01[0]*q[3])+(q[1]*dq_drr01[2]+dq_drr01[1]*q[2]));
546 114 : drotation_drr01[2][0]=2*(+(q[0]*dq_drr01[2]+dq_drr01[0]*q[2])+(q[1]*dq_drr01[3]+dq_drr01[1]*q[3]));
547 114 : drotation_drr01[2][1]=2*(-(q[0]*dq_drr01[1]+dq_drr01[0]*q[1])+(q[2]*dq_drr01[3]+dq_drr01[2]*q[3]));
548 : }
549 :
550 : double prefactor=2.0;
551 :
552 546363 : if(!squared && alEqDis) prefactor*=0.5/sqrt(dist);
553 :
554 : // if "safe", recompute dist here to a better accuracy
555 : if(safe || !alEqDis) dist=0.0;
556 :
557 : // If safe is set to "false", MSD is taken from the eigenvalue of the M matrix
558 : // If safe is set to "true", MSD is recomputed from the rotational matrix
559 : // For some reason, this last approach leads to less numerical noise but adds an overhead
560 :
561 546477 : Tensor ddist_drotation;
562 546477 : Vector ddist_dcpositions;
563 :
564 : // third expensive loop: derivatives
565 44117285 : for(unsigned iat=0; iat<n; iat++) {
566 65356212 : Vector d(positions[iat]-cpositions - matmul(rotation,reference[iat]));
567 : if(alEqDis) {
568 : // there is no need for derivatives of rotation and shift here as it is by construction zero
569 : // (similar to Hellman-Feynman forces)
570 43566456 : derivatives[iat]= prefactor*align[iat]*d;
571 4921522 : if(safe) dist+=align[iat]*modulo2(d);
572 : } else {
573 : // the case for align != displace is different, sob:
574 2176 : dist+=displace[iat]*modulo2(d);
575 : // these are the derivatives assuming the roto-translation as frozen
576 4352 : derivatives[iat]=2*displace[iat]*d;
577 : // here I accumulate derivatives wrt rotation matrix ..
578 4352 : ddist_drotation+=-2*displace[iat]*extProduct(d,reference[iat]);
579 : // .. and cpositions
580 2176 : ddist_dcpositions+=-2*displace[iat]*d;
581 : }
582 : }
583 :
584 : if(!alEqDis) {
585 114 : Tensor ddist_drr01;
586 1482 : for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) ddist_drr01+=ddist_drotation[i][j]*drotation_drr01[i][j];
587 4466 : for(unsigned iat=0; iat<n; iat++) {
588 : // this is propagating to positions.
589 : // I am implicitly using the derivative of rr01 wrt positions here
590 8704 : derivatives[iat]+=matmul(ddist_drr01,reference[iat])*align[iat];
591 4352 : derivatives[iat]+=ddist_dcpositions*align[iat];
592 : }
593 : }
594 546477 : if(!squared) {
595 74171 : dist=sqrt(dist);
596 : if(!alEqDis) {
597 114 : double xx=0.5/dist;
598 4466 : for(unsigned iat=0; iat<n; iat++) derivatives[iat]*=xx;
599 : }
600 : }
601 :
602 546477 : return dist;
603 : }
604 : #else
605 : /// note that this method is intended to be repeatedly invoked
606 : /// when the reference does already have the center subtracted
607 : /// but the position has not calculated center and not subtracted
608 : template <bool safe,bool alEqDis>
609 : double RMSD::optimalAlignment(const std::vector<double> & align,
610 : const std::vector<double> & displace,
611 : const std::vector<Vector> & positions,
612 : const std::vector<Vector> & reference,
613 : std::vector<Vector> & derivatives,
614 : bool squared) const {
615 : //std::cerr<<"setting up the core data \n";
616 : RMSDCoreData cd(align,displace,positions,reference);
617 :
618 : // transfer the settings for the center to let the CoreCalc deal with it
619 : cd.setPositionsCenterIsRemoved(positions_center_is_removed);
620 : if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
621 : else {cd.calcPositionsCenter();};
622 :
623 : cd.setReferenceCenterIsRemoved(reference_center_is_removed);
624 : if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
625 : else {cd.setReferenceCenter(reference_center);}
626 :
627 : // Perform the diagonalization and all the needed stuff
628 : cd.doCoreCalc(safe,alEqDis);
629 : // make the core calc distance
630 : double dist=cd.getDistance(squared);
631 : // make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
632 : derivatives=cd.getDDistanceDPositions();
633 : return dist;
634 : }
635 : #endif
636 : template <bool safe,bool alEqDis>
637 1 : double RMSD::optimalAlignment_DDistDRef(const std::vector<double> & align,
638 : const std::vector<double> & displace,
639 : const std::vector<Vector> & positions,
640 : const std::vector<Vector> & reference,
641 : std::vector<Vector> & derivatives,
642 : std::vector<Vector> & ddistdref,
643 : bool squared) const {
644 : //initialize the data into the structure
645 : // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
646 2 : RMSDCoreData cd(align,displace,positions,reference);
647 : // transfer the settings for the center to let the CoreCalc deal with it
648 : // transfer the settings for the center to let the CoreCalc deal with it
649 1 : cd.setPositionsCenterIsRemoved(positions_center_is_removed);
650 1 : if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
651 1 : else {cd.calcPositionsCenter();};
652 :
653 1 : cd.setReferenceCenterIsRemoved(reference_center_is_removed);
654 1 : if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
655 1 : else {cd.setReferenceCenter(reference_center);}
656 :
657 : // Perform the diagonalization and all the needed stuff
658 1 : cd.doCoreCalc(safe,alEqDis);
659 : // make the core calc distance
660 1 : double dist=cd.getDistance(squared);
661 : // make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
662 2 : derivatives=cd.getDDistanceDPositions();
663 2 : ddistdref=cd.getDDistanceDReference();
664 1 : return dist;
665 : }
666 :
667 : template <bool safe,bool alEqDis>
668 0 : double RMSD::optimalAlignment_SOMA(const std::vector<double> & align,
669 : const std::vector<double> & displace,
670 : const std::vector<Vector> & positions,
671 : const std::vector<Vector> & reference,
672 : std::vector<Vector> & derivatives,
673 : std::vector<Vector> & ddistdref,
674 : bool squared) const {
675 : //initialize the data into the structure
676 : // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
677 0 : RMSDCoreData cd(align,displace,positions,reference);
678 : // transfer the settings for the center to let the CoreCalc deal with it
679 : // transfer the settings for the center to let the CoreCalc deal with it
680 0 : cd.setPositionsCenterIsRemoved(positions_center_is_removed);
681 0 : if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
682 0 : else {cd.calcPositionsCenter();};
683 :
684 0 : cd.setReferenceCenterIsRemoved(reference_center_is_removed);
685 0 : if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
686 0 : else {cd.setReferenceCenter(reference_center);}
687 :
688 : // Perform the diagonalization and all the needed stuff
689 0 : cd.doCoreCalc(safe,alEqDis);
690 : // make the core calc distance
691 0 : double dist=cd.getDistance(squared);
692 : // make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
693 0 : derivatives=cd.getDDistanceDPositions();
694 0 : ddistdref=cd.getDDistanceDReferenceSOMA();
695 0 : return dist;
696 : }
697 :
698 :
699 : template <bool safe,bool alEqDis>
700 0 : double RMSD::optimalAlignment_DDistDRef_Rot_DRotDPos(const std::vector<double> & align,
701 : const std::vector<double> & displace,
702 : const std::vector<Vector> & positions,
703 : const std::vector<Vector> & reference,
704 : std::vector<Vector> & derivatives,
705 : std::vector<Vector> & ddistdref,
706 : Tensor & Rotation,
707 : Matrix<std::vector<Vector> > &DRotDPos,
708 : bool squared) const {
709 : //initialize the data into the structure
710 : // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
711 0 : RMSDCoreData cd(align,displace,positions,reference);
712 : // transfer the settings for the center to let the CoreCalc deal with it
713 : // transfer the settings for the center to let the CoreCalc deal with it
714 0 : cd.setPositionsCenterIsRemoved(positions_center_is_removed);
715 0 : if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
716 0 : else {cd.calcPositionsCenter();};
717 :
718 0 : cd.setReferenceCenterIsRemoved(reference_center_is_removed);
719 0 : if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
720 0 : else {cd.setReferenceCenter(reference_center);}
721 :
722 : // Perform the diagonalization and all the needed stuff
723 0 : cd.doCoreCalc(safe,alEqDis);
724 : // make the core calc distance
725 0 : double dist=cd.getDistance(squared);
726 : // make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
727 0 : derivatives=cd.getDDistanceDPositions();
728 0 : ddistdref=cd.getDDistanceDReference();
729 : // get the rotation matrix
730 0 : Rotation=cd.getRotationMatrixReferenceToPositions();
731 : // get its derivative
732 0 : DRotDPos=cd.getDRotationDPositions();
733 0 : return dist;
734 : }
735 :
736 : template <bool safe,bool alEqDis>
737 0 : double RMSD::optimalAlignment_DDistDRef_Rot_DRotDPos_DRotDRef(const std::vector<double> & align,
738 : const std::vector<double> & displace,
739 : const std::vector<Vector> & positions,
740 : const std::vector<Vector> & reference,
741 : std::vector<Vector> & derivatives,
742 : std::vector<Vector> & ddistdref,
743 : Tensor & Rotation,
744 : Matrix<std::vector<Vector> > &DRotDPos,
745 : Matrix<std::vector<Vector> > &DRotDRef,
746 : bool squared) const {
747 : //initialize the data into the structure
748 : // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
749 0 : RMSDCoreData cd(align,displace,positions,reference);
750 : // transfer the settings for the center to let the CoreCalc deal with it
751 : // transfer the settings for the center to let the CoreCalc deal with it
752 0 : cd.setPositionsCenterIsRemoved(positions_center_is_removed);
753 0 : if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
754 0 : else {cd.calcPositionsCenter();};
755 :
756 0 : cd.setReferenceCenterIsRemoved(reference_center_is_removed);
757 0 : if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
758 0 : else {cd.setReferenceCenter(reference_center);}
759 :
760 : // Perform the diagonalization and all the needed stuff
761 0 : cd.doCoreCalc(safe,alEqDis);
762 : // make the core calc distance
763 0 : double dist=cd.getDistance(squared);
764 : // make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
765 0 : derivatives=cd.getDDistanceDPositions();
766 0 : ddistdref=cd.getDDistanceDReference();
767 : // get the rotation matrix
768 0 : Rotation=cd.getRotationMatrixReferenceToPositions();
769 : // get its derivative
770 0 : DRotDPos=cd.getDRotationDPositions();
771 0 : DRotDRef=cd.getDRotationDReference();
772 0 : return dist;
773 : }
774 :
775 : template <bool safe,bool alEqDis>
776 1092 : double RMSD::optimalAlignment_Rot_DRotDRr01(const std::vector<double> & align,
777 : const std::vector<double> & displace,
778 : const std::vector<Vector> & positions,
779 : const std::vector<Vector> & reference,
780 : Tensor & Rotation,
781 : std::array<std::array<Tensor,3>,3> & DRotDRr01,
782 : bool squared) const {
783 : //initialize the data into the structure
784 : // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
785 2184 : RMSDCoreData cd(align,displace,positions,reference);
786 : // transfer the settings for the center to let the CoreCalc deal with it
787 1092 : cd.setPositionsCenterIsRemoved(positions_center_is_removed);
788 1092 : if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
789 1092 : else {cd.calcPositionsCenter();};
790 :
791 1092 : cd.setReferenceCenterIsRemoved(reference_center_is_removed);
792 1092 : if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
793 1092 : else {cd.setReferenceCenter(reference_center);}
794 :
795 : // Perform the diagonalization and all the needed stuff
796 1092 : cd.doCoreCalc(safe,alEqDis);
797 : // make the core calc distance
798 1092 : double dist=cd.getDistance(squared);
799 : // get the rotation matrix
800 1092 : Rotation=cd.getRotationMatrixReferenceToPositions();
801 : //get detivative w.r.t. rr01
802 1092 : DRotDRr01=cd.getDRotationDRr01();
803 1092 : return dist;
804 : }
805 :
806 : template <bool safe,bool alEqDis>
807 672 : double RMSD::optimalAlignment_Rot(const std::vector<double> & align,
808 : const std::vector<double> & displace,
809 : const std::vector<Vector> & positions,
810 : const std::vector<Vector> & reference,
811 : std::vector<Vector> & derivatives,
812 : Tensor & Rotation,
813 : bool squared) const {
814 : //initialize the data into the structure
815 : // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
816 1344 : RMSDCoreData cd(align,displace,positions,reference);
817 : // transfer the settings for the center to let the CoreCalc deal with it
818 672 : cd.setPositionsCenterIsRemoved(positions_center_is_removed);
819 672 : if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
820 672 : else {cd.calcPositionsCenter();};
821 :
822 672 : cd.setReferenceCenterIsRemoved(reference_center_is_removed);
823 672 : if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
824 672 : else {cd.setReferenceCenter(reference_center);}
825 :
826 : // Perform the diagonalization and all the needed stuff
827 672 : cd.doCoreCalc(safe,alEqDis);
828 : // make the core calc distance
829 672 : double dist=cd.getDistance(squared);
830 : // make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
831 1344 : derivatives=cd.getDDistanceDPositions();
832 : // get the rotation matrix
833 672 : Rotation=cd.getRotationMatrixReferenceToPositions();
834 672 : return dist;
835 : }
836 :
837 : template <bool safe,bool alEqDis>
838 45192 : double RMSD::optimalAlignmentWithCloseStructure(const std::vector<double> & align,
839 : const std::vector<double> & displace,
840 : const std::vector<Vector> & positions,
841 : const std::vector<Vector> & reference,
842 : std::vector<Vector> & derivatives,
843 : Tensor & rotationPosClose,
844 : Tensor & rotationRefClose,
845 : std::array<std::array<Tensor,3>,3> & drotationPosCloseDrr01,
846 : bool squared) const {
847 : //initialize the data into the structure
848 : // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
849 90384 : RMSDCoreData cd(align,displace,positions,reference);
850 : // transfer the settings for the center to let the CoreCalc deal with it
851 45192 : cd.setPositionsCenterIsRemoved(positions_center_is_removed);
852 45192 : if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
853 45192 : else {cd.calcPositionsCenter();};
854 :
855 45192 : cd.setReferenceCenterIsRemoved(reference_center_is_removed);
856 45192 : if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
857 45192 : else {cd.setReferenceCenter(reference_center);}
858 :
859 : // instead of diagonalization, approximate with saved rotation matrix
860 45192 : cd.doCoreCalcWithCloseStructure(safe,alEqDis, rotationPosClose, rotationRefClose, drotationPosCloseDrr01);
861 : // make the core calc distance
862 45192 : double dist=cd.getDistance(squared);
863 : // make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
864 90384 : derivatives=cd.getDDistanceDPositions();
865 45192 : return dist;
866 : }
867 :
868 :
869 : template <bool safe,bool alEqDis>
870 4441 : double RMSD::optimalAlignment_PCA(const std::vector<double> & align,
871 : const std::vector<double> & displace,
872 : const std::vector<Vector> & positions,
873 : const std::vector<Vector> & reference,
874 : std::vector<Vector> & alignedpositions,
875 : std::vector<Vector> & centeredpositions,
876 : std::vector<Vector> & centeredreference,
877 : Tensor & Rotation,
878 : std::vector<Vector> & DDistDPos,
879 : Matrix<std::vector<Vector> > & DRotDPos,
880 : bool squared) const {
881 : //initialize the data into the structure
882 : // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
883 8882 : RMSDCoreData cd(align,displace,positions,reference);
884 : // transfer the settings for the center to let the CoreCalc deal with it
885 4441 : cd.setPositionsCenterIsRemoved(positions_center_is_removed);
886 4441 : if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
887 4441 : else {cd.calcPositionsCenter();};
888 :
889 4441 : cd.setReferenceCenterIsRemoved(reference_center_is_removed);
890 4441 : if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
891 4441 : else {cd.setReferenceCenter(reference_center);}
892 :
893 : // Perform the diagonalization and all the needed stuff
894 4441 : cd.doCoreCalc(safe,alEqDis);
895 : // make the core calc distance
896 4441 : double dist=cd.getDistance(squared);
897 : // make the derivatives by using pieces calculated in coreCalc (probably the best is just to copy the vector...)
898 8882 : DDistDPos=cd.getDDistanceDPositions();
899 : // get the rotation matrix
900 4441 : Rotation=cd.getRotationMatrixPositionsToReference();
901 : // get its derivative
902 8882 : DRotDPos=cd.getDRotationDPositions(true); // this gives back the inverse
903 : // get aligned positions
904 8882 : alignedpositions=cd.getAlignedPositionsToReference();
905 : // get centered positions
906 8882 : centeredpositions=cd.getCenteredPositions();
907 : // get centered reference
908 8882 : centeredreference=cd.getCenteredReference();
909 4441 : return dist;
910 : }
911 :
912 :
913 : template <bool safe,bool alEqDis>
914 48 : double RMSD::optimalAlignment_Fit(const std::vector<double> & align,
915 : const std::vector<double> & displace,
916 : const std::vector<Vector> & positions,
917 : const std::vector<Vector> & reference,
918 : Tensor & Rotation,
919 : Matrix<std::vector<Vector> > & DRotDPos,
920 : std::vector<Vector> & centeredpositions,
921 : Vector & center_positions,
922 : bool squared) {
923 : //initialize the data into the structure
924 : // typically the positions do not have the com neither calculated nor subtracted. This layer takes care of this business
925 96 : RMSDCoreData cd(align,displace,positions,reference);
926 : // transfer the settings for the center to let the CoreCalc deal with it
927 48 : cd.setPositionsCenterIsRemoved(positions_center_is_removed);
928 48 : if(positions_center_is_calculated) {cd.setPositionsCenter(positions_center);}
929 48 : else {cd.calcPositionsCenter();};
930 :
931 48 : cd.setReferenceCenterIsRemoved(reference_center_is_removed);
932 48 : if(!reference_center_is_calculated) {cd.calcReferenceCenter();}
933 48 : else {cd.setReferenceCenter(reference_center);}
934 :
935 : // Perform the diagonalization and all the needed stuff
936 48 : cd.doCoreCalc(safe,alEqDis);
937 : // make the core calc distance
938 48 : double dist=cd.getDistance(squared);
939 : // get the rotation matrix
940 48 : Rotation=cd.getRotationMatrixPositionsToReference();
941 : // get its derivative
942 96 : DRotDPos=cd.getDRotationDPositions(true); // this gives back the inverse
943 : // get centered positions
944 96 : centeredpositions=cd.getCenteredPositions();
945 : // get center
946 48 : center_positions=cd.getPositionsCenter();
947 48 : return dist;
948 : }
949 :
950 :
951 :
952 :
953 :
954 :
955 : /// This calculates the elements needed by the quaternion to calculate everything that is needed
956 : /// additional calls retrieve different components
957 : /// note that this considers that the centers of both reference and positions are already setted
958 : /// but automatically should properly account for non removed components: if not removed then it
959 : /// removes prior to calculation of the alignment
960 6254 : void RMSDCoreData::doCoreCalc(bool safe,bool alEqDis, bool only_rotation) {
961 :
962 6254 : retrieve_only_rotation=only_rotation;
963 12508 : const unsigned n=static_cast<unsigned int>(reference.size());
964 :
965 6254 : plumed_massert(creference_is_calculated,"the center of the reference frame must be already provided at this stage");
966 6254 : plumed_massert(cpositions_is_calculated,"the center of the positions frame must be already provided at this stage");
967 :
968 : // This is the trace of positions*positions + reference*reference
969 6254 : rr00=0.;
970 6254 : rr11=0.;
971 : // This is positions*reference
972 6254 : Tensor rr01;
973 : // center of mass managing: must subtract the center from the position or not?
974 6254 : Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions;
975 6254 : Vector cr; cr.zero(); if(!creference_is_removed)cr=creference;
976 : // second expensive loop: compute second moments wrt centers
977 186678 : for(unsigned iat=0; iat<n; iat++) {
978 180424 : double w=align[iat];
979 270636 : rr00+=dotProduct(positions[iat]-cp,positions[iat]-cp)*w;
980 270636 : rr11+=dotProduct(reference[iat]-cr,reference[iat]-cr)*w;
981 270636 : rr01+=Tensor(positions[iat]-cp,reference[iat]-cr)*w;
982 : }
983 :
984 : // the quaternion matrix: this is internal
985 : Matrix<double> m=Matrix<double>(4,4);
986 :
987 6254 : m[0][0]=2.0*(-rr01[0][0]-rr01[1][1]-rr01[2][2]);
988 6254 : m[1][1]=2.0*(-rr01[0][0]+rr01[1][1]+rr01[2][2]);
989 6254 : m[2][2]=2.0*(+rr01[0][0]-rr01[1][1]+rr01[2][2]);
990 6254 : m[3][3]=2.0*(+rr01[0][0]+rr01[1][1]-rr01[2][2]);
991 6254 : m[0][1]=2.0*(-rr01[1][2]+rr01[2][1]);
992 6254 : m[0][2]=2.0*(+rr01[0][2]-rr01[2][0]);
993 6254 : m[0][3]=2.0*(-rr01[0][1]+rr01[1][0]);
994 6254 : m[1][2]=2.0*(-rr01[0][1]-rr01[1][0]);
995 6254 : m[1][3]=2.0*(-rr01[0][2]-rr01[2][0]);
996 6254 : m[2][3]=2.0*(-rr01[1][2]-rr01[2][1]);
997 6254 : m[1][0] = m[0][1];
998 6254 : m[2][0] = m[0][2];
999 6254 : m[2][1] = m[1][2];
1000 6254 : m[3][0] = m[0][3];
1001 6254 : m[3][1] = m[1][3];
1002 6254 : m[3][2] = m[2][3];
1003 :
1004 :
1005 31270 : Tensor dm_drr01[4][4];
1006 6254 : if(!alEqDis or !retrieve_only_rotation) {
1007 6254 : dm_drr01[0][0] = 2.0*Tensor(-1.0, 0.0, 0.0, 0.0,-1.0, 0.0, 0.0, 0.0,-1.0);
1008 6254 : dm_drr01[1][1] = 2.0*Tensor(-1.0, 0.0, 0.0, 0.0,+1.0, 0.0, 0.0, 0.0,+1.0);
1009 6254 : dm_drr01[2][2] = 2.0*Tensor(+1.0, 0.0, 0.0, 0.0,-1.0, 0.0, 0.0, 0.0,+1.0);
1010 6254 : dm_drr01[3][3] = 2.0*Tensor(+1.0, 0.0, 0.0, 0.0,+1.0, 0.0, 0.0, 0.0,-1.0);
1011 6254 : dm_drr01[0][1] = 2.0*Tensor( 0.0, 0.0, 0.0, 0.0, 0.0,-1.0, 0.0,+1.0, 0.0);
1012 6254 : dm_drr01[0][2] = 2.0*Tensor( 0.0, 0.0,+1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0);
1013 6254 : dm_drr01[0][3] = 2.0*Tensor( 0.0,-1.0, 0.0, +1.0, 0.0, 0.0, 0.0, 0.0, 0.0);
1014 6254 : dm_drr01[1][2] = 2.0*Tensor( 0.0,-1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0);
1015 6254 : dm_drr01[1][3] = 2.0*Tensor( 0.0, 0.0,-1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0);
1016 6254 : dm_drr01[2][3] = 2.0*Tensor( 0.0, 0.0, 0.0, 0.0, 0.0,-1.0, 0.0,-1.0, 0.0);
1017 6254 : dm_drr01[1][0] = dm_drr01[0][1];
1018 6254 : dm_drr01[2][0] = dm_drr01[0][2];
1019 6254 : dm_drr01[2][1] = dm_drr01[1][2];
1020 6254 : dm_drr01[3][0] = dm_drr01[0][3];
1021 6254 : dm_drr01[3][1] = dm_drr01[1][3];
1022 6254 : dm_drr01[3][2] = dm_drr01[2][3];
1023 : }
1024 :
1025 :
1026 6254 : int diagerror=diagMat(m, eigenvals, eigenvecs );
1027 :
1028 6254 : if (diagerror!=0) {
1029 : std::string sdiagerror;
1030 0 : Tools::convert(diagerror,sdiagerror);
1031 0 : std::string msg="DIAGONALIZATION FAILED WITH ERROR CODE "+sdiagerror;
1032 0 : plumed_merror(msg);
1033 : }
1034 :
1035 12508 : Vector4d q(eigenvecs[0][0],eigenvecs[0][1],eigenvecs[0][2],eigenvecs[0][3]);
1036 : // cerr<<"EIGENVAL "<<eigenvals[0]<<" "<<eigenvals[1]<<" "<<eigenvals[2]<<" "<<eigenvals[3]<<"\n";
1037 :
1038 31270 : Tensor dq_drr01[4];
1039 6254 : if(!alEqDis or !only_rotation) {
1040 : double dq_dm[4][4][4];
1041 431526 : for(unsigned i=0; i<4; i++) for(unsigned j=0; j<4; j++) for(unsigned k=0; k<4; k++) {
1042 : double tmp=0.0;
1043 : // perturbation theory for matrix m
1044 4002560 : for(unsigned l=1; l<4; l++) tmp+=eigenvecs[l][j]*eigenvecs[l][i]/(eigenvals[0]-eigenvals[l])*eigenvecs[0][k];
1045 400256 : dq_dm[i][j][k]=tmp;
1046 : }
1047 : // propagation to _drr01
1048 56286 : for(unsigned i=0; i<4; i++) {
1049 25016 : Tensor tmp;
1050 525336 : for(unsigned j=0; j<4; j++) for(unsigned k=0; k<4; k++) {
1051 400256 : tmp+=dq_dm[i][j][k]*dm_drr01[j][k];
1052 : }
1053 25016 : dq_drr01[i]=tmp;
1054 : }
1055 : }
1056 :
1057 : // This is the rotation matrix that brings reference to positions
1058 : // i.e. matmul(rotation,reference[iat])+shift is fitted to positions[iat]
1059 :
1060 6254 : rotation[0][0]=q[0]*q[0]+q[1]*q[1]-q[2]*q[2]-q[3]*q[3];
1061 6254 : rotation[1][1]=q[0]*q[0]-q[1]*q[1]+q[2]*q[2]-q[3]*q[3];
1062 6254 : rotation[2][2]=q[0]*q[0]-q[1]*q[1]-q[2]*q[2]+q[3]*q[3];
1063 6254 : rotation[0][1]=2*(+q[0]*q[3]+q[1]*q[2]);
1064 6254 : rotation[0][2]=2*(-q[0]*q[2]+q[1]*q[3]);
1065 6254 : rotation[1][2]=2*(+q[0]*q[1]+q[2]*q[3]);
1066 6254 : rotation[1][0]=2*(-q[0]*q[3]+q[1]*q[2]);
1067 6254 : rotation[2][0]=2*(+q[0]*q[2]+q[1]*q[3]);
1068 6254 : rotation[2][1]=2*(-q[0]*q[1]+q[2]*q[3]);
1069 :
1070 :
1071 6254 : if(!alEqDis or !only_rotation) {
1072 12508 : drotation_drr01[0][0]=2*q[0]*dq_drr01[0]+2*q[1]*dq_drr01[1]-2*q[2]*dq_drr01[2]-2*q[3]*dq_drr01[3];
1073 12508 : drotation_drr01[1][1]=2*q[0]*dq_drr01[0]-2*q[1]*dq_drr01[1]+2*q[2]*dq_drr01[2]-2*q[3]*dq_drr01[3];
1074 12508 : drotation_drr01[2][2]=2*q[0]*dq_drr01[0]-2*q[1]*dq_drr01[1]-2*q[2]*dq_drr01[2]+2*q[3]*dq_drr01[3];
1075 12508 : drotation_drr01[0][1]=2*(+(q[0]*dq_drr01[3]+dq_drr01[0]*q[3])+(q[1]*dq_drr01[2]+dq_drr01[1]*q[2]));
1076 12508 : drotation_drr01[0][2]=2*(-(q[0]*dq_drr01[2]+dq_drr01[0]*q[2])+(q[1]*dq_drr01[3]+dq_drr01[1]*q[3]));
1077 12508 : drotation_drr01[1][2]=2*(+(q[0]*dq_drr01[1]+dq_drr01[0]*q[1])+(q[2]*dq_drr01[3]+dq_drr01[2]*q[3]));
1078 12508 : drotation_drr01[1][0]=2*(-(q[0]*dq_drr01[3]+dq_drr01[0]*q[3])+(q[1]*dq_drr01[2]+dq_drr01[1]*q[2]));
1079 12508 : drotation_drr01[2][0]=2*(+(q[0]*dq_drr01[2]+dq_drr01[0]*q[2])+(q[1]*dq_drr01[3]+dq_drr01[1]*q[3]));
1080 12508 : drotation_drr01[2][1]=2*(-(q[0]*dq_drr01[1]+dq_drr01[0]*q[1])+(q[2]*dq_drr01[3]+dq_drr01[2]*q[3]));
1081 : }
1082 :
1083 6254 : d.resize(n);
1084 :
1085 : // calculate rotation matrix derivatives and components distances needed for components only when align!=displacement
1086 6254 : if(!alEqDis)ddist_drotation.zero();
1087 : #pragma omp simd
1088 : for(unsigned iat=0; iat<n; iat++) {
1089 : // components differences: this is useful externally
1090 360848 : d[iat]=positions[iat]-cp - matmul(rotation,reference[iat]-cr);
1091 : //cerr<<"D "<<iat<<" "<<d[iat][0]<<" "<<d[iat][1]<<" "<<d[iat][2]<<"\n";
1092 : }
1093 : // ddist_drotation if needed
1094 6254 : if(!alEqDis or !only_rotation)
1095 186678 : for (unsigned iat=0; iat<n; iat++)
1096 360848 : ddist_drotation+=-2*displace[iat]*extProduct(d[iat],reference[iat]-cr);
1097 :
1098 6254 : if(!alEqDis or !only_rotation) {
1099 6254 : ddist_drr01.zero();
1100 81302 : for(unsigned i=0; i<3; i++) for(unsigned j=0; j<3; j++) ddist_drr01+=ddist_drotation[i][j]*drotation_drr01[i][j];
1101 : }
1102 : // transfer this bools to the cd so that this settings will be reflected in the other calls
1103 6254 : this->alEqDis=alEqDis;
1104 6254 : this->safe=safe;
1105 6254 : isInitialized=true;
1106 :
1107 6254 : }
1108 : /// just retrieve the distance already calculated
1109 51446 : double RMSDCoreData::getDistance( bool squared) {
1110 :
1111 51446 : if(!isInitialized)plumed_merror("getDistance cannot calculate the distance without being initialized first by doCoreCalc ");
1112 :
1113 : double localDist=0.0;
1114 102892 : const unsigned n=static_cast<unsigned int>(reference.size());
1115 51446 : if(safe || !alEqDis) localDist=0.0;
1116 : else
1117 0 : localDist=eigenvals[0]+rr00+rr11;
1118 102892 : #pragma omp simd reduction(+:localDist)
1119 : for(unsigned iat=0; iat<n; iat++) {
1120 677708 : if(alEqDis) {
1121 2029839 : if(safe) localDist+=align[iat]*modulo2(d[iat]);
1122 : } else {
1123 3285 : localDist+=displace[iat]*modulo2(d[iat]);
1124 : }
1125 : }
1126 51446 : if(!squared) {
1127 75 : dist=sqrt(localDist);
1128 75 : distanceIsMSD=false;
1129 : } else {
1130 51371 : dist=localDist;
1131 51371 : distanceIsMSD=true;
1132 : }
1133 51446 : hasDistance=true;
1134 51446 : return dist;
1135 : }
1136 :
1137 45192 : void RMSDCoreData::doCoreCalcWithCloseStructure(bool safe,bool alEqDis, Tensor & rotationPosClose, Tensor & rotationRefClose, std::array<std::array<Tensor,3>,3> & drotationPosCloseDrr01) {
1138 :
1139 90384 : unsigned natoms = reference.size();
1140 45192 : Tensor ddist_drxy;
1141 45192 : ddist_drr01.zero();
1142 45192 : d.resize(natoms);
1143 :
1144 : // center of mass managing: must subtract the center from the position or not?
1145 45192 : Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions;
1146 45192 : Vector cr; cr.zero(); if(!creference_is_removed)cr=creference;
1147 : //distance = \sum_{n=0}^{N} w_n(x_n-cpos-R_{XY} R_{AY} a_n)^2
1148 :
1149 45192 : Tensor rotation = matmul(rotationPosClose, rotationRefClose);
1150 :
1151 : #pragma omp simd
1152 : for (unsigned iat=0; iat<natoms; iat++) {
1153 2349984 : d[iat] = positions[iat] - cp - matmul(rotation, reference[iat]-cr);
1154 : }
1155 45192 : if (!alEqDis) {
1156 0 : for (unsigned iat=0; iat<natoms; iat++) {
1157 : //dist = \sum w_i(x_i - cpos - R_xy * R_ay * a_i)
1158 0 : ddist_drxy += -2*displace[iat]*extProduct(matmul(d[iat], rotationRefClose), reference[iat]-cr);
1159 : }
1160 : }
1161 :
1162 45192 : if (!alEqDis) {
1163 0 : for(unsigned i=0; i<3; i++)
1164 0 : for(unsigned j=0; j<3; j++)
1165 0 : ddist_drr01+=ddist_drxy[i][j]*drotationPosCloseDrr01[i][j];
1166 : }
1167 45192 : this->alEqDis=alEqDis;
1168 45192 : this->safe=safe;
1169 45192 : isInitialized=true;
1170 45192 : }
1171 :
1172 50306 : std::vector<Vector> RMSDCoreData::getDDistanceDPositions() {
1173 : std::vector<Vector> derivatives;
1174 100612 : const unsigned n=static_cast<unsigned int>(reference.size());
1175 50306 : Vector ddist_dcpositions;
1176 50306 : derivatives.resize(n);
1177 : double prefactor=1.0;
1178 50306 : if(!distanceIsMSD) prefactor*=0.5/dist;
1179 50306 : plumed_massert(!retrieve_only_rotation,"You used only_rotation=true in doCoreCalc therefore you cannot retrieve this information now");
1180 50306 : if(!hasDistance)plumed_merror("getDPositionsDerivatives needs to calculate the distance via getDistance first !");
1181 50306 : if(!isInitialized)plumed_merror("getDPositionsDerivatives needs to initialize the coreData first!");
1182 50306 : Vector csum;
1183 1376850 : for(unsigned iat=0; iat<n; iat++) {
1184 663272 : if(alEqDis) {
1185 : // there is no need for derivatives of rotation and shift here as it is by construction zero
1186 : // (similar to Hellman-Feynman forces)
1187 2649668 : derivatives[iat]= 2*prefactor*align[iat]*d[iat];
1188 : } else {
1189 : // these are the derivatives assuming the roto-translation as frozen
1190 2565 : Vector tmp1=2*displace[iat]*d[iat];
1191 855 : derivatives[iat]=tmp1;
1192 : // derivative of cpositions
1193 855 : ddist_dcpositions+=-tmp1;
1194 : // these needed for com corrections
1195 2565 : Vector tmp2=matmul(ddist_drr01,reference[iat]-creference)*align[iat];
1196 855 : derivatives[iat]+=tmp2;
1197 855 : csum+=tmp2;
1198 : }
1199 : }
1200 :
1201 50306 : if(!alEqDis)
1202 : #pragma omp simd
1203 3420 : for(unsigned iat=0; iat<n; iat++) {derivatives[iat]= prefactor*(derivatives[iat]+(ddist_dcpositions-csum)*align[iat]); }
1204 :
1205 50306 : return derivatives;
1206 : }
1207 :
1208 1 : std::vector<Vector> RMSDCoreData::getDDistanceDReference() {
1209 : std::vector<Vector> derivatives;
1210 2 : const unsigned n=static_cast<unsigned int>(reference.size());
1211 1 : Vector ddist_dcreference;
1212 1 : derivatives.resize(n);
1213 : double prefactor=1.0;
1214 1 : if(!distanceIsMSD) prefactor*=0.5/dist;
1215 1 : Vector csum;
1216 :
1217 1 : plumed_massert(!retrieve_only_rotation,"You used only_rotation=true in doCoreCalc therefore you cannot retrieve this information now");
1218 1 : if(!hasDistance)plumed_merror("getDDistanceDReference needs to calculate the distance via getDistance first !");
1219 1 : if(!isInitialized)plumed_merror("getDDistanceDReference to initialize the coreData first!");
1220 : // get the transpose rotation
1221 1 : Tensor t_rotation=rotation.transpose();
1222 1 : Tensor t_ddist_drr01=ddist_drr01.transpose();
1223 :
1224 : // third expensive loop: derivatives
1225 1711 : for(unsigned iat=0; iat<n; iat++) {
1226 855 : if(alEqDis) {
1227 : // there is no need for derivatives of rotation and shift here as it is by construction zero
1228 : // (similar to Hellman-Feynman forces)
1229 : //TODO: check this derivative down here
1230 0 : derivatives[iat]= -2*prefactor*align[iat]*matmul(t_rotation,d[iat]);
1231 : } else {
1232 : // these are the derivatives assuming the roto-translation as frozen
1233 2565 : Vector tmp1=2*displace[iat]*matmul(t_rotation,d[iat]);
1234 855 : derivatives[iat]= -tmp1;
1235 : // derivative of cpositions
1236 855 : ddist_dcreference+=tmp1;
1237 : // these below are needed for com correction
1238 2565 : Vector tmp2=matmul(t_ddist_drr01,positions[iat]-cpositions)*align[iat];
1239 855 : derivatives[iat]+=tmp2;
1240 855 : csum+=tmp2;
1241 : }
1242 : }
1243 :
1244 1 : if(!alEqDis)
1245 : #pragma omp simd
1246 3420 : for(unsigned iat=0; iat<n; iat++) {derivatives[iat]= prefactor*(derivatives[iat]+(ddist_dcreference-csum)*align[iat]);}
1247 :
1248 1 : return derivatives;
1249 : }
1250 :
1251 : /// this version does not calculate the derivative of rotation matrix as needed for SOMA
1252 0 : std::vector<Vector> RMSDCoreData::getDDistanceDReferenceSOMA() {
1253 : std::vector<Vector> derivatives;
1254 0 : const unsigned n=static_cast<unsigned int>(reference.size());
1255 0 : Vector ddist_dcreference;
1256 0 : derivatives.resize(n);
1257 : double prefactor=1.0;
1258 0 : if(!distanceIsMSD) prefactor*=0.5/dist;
1259 0 : Vector csum,tmp1,tmp2;
1260 :
1261 0 : plumed_massert(!retrieve_only_rotation,"You used only_rotation=true in doCoreCalc therefore you cannot retrieve this information now");
1262 0 : if(!hasDistance)plumed_merror("getDDistanceDReference needs to calculate the distance via getDistance first !");
1263 0 : if(!isInitialized)plumed_merror("getDDistanceDReference to initialize the coreData first!");
1264 : // get the transpose rotation
1265 0 : Tensor t_rotation=rotation.transpose();
1266 :
1267 : // third expensive loop: derivatives
1268 0 : for(unsigned iat=0; iat<n; iat++) {
1269 0 : if(alEqDis) {
1270 : // there is no need for derivatives of rotation and shift here as it is by construction zero
1271 : // (similar to Hellman-Feynman forces)
1272 : //TODO: check this derivative down here
1273 0 : derivatives[iat]= -2*prefactor*align[iat]*matmul(t_rotation,d[iat]);
1274 : } else {
1275 : // these are the derivatives assuming the roto-translation as frozen
1276 0 : tmp1=2*displace[iat]*matmul(t_rotation,d[iat]);
1277 0 : derivatives[iat]= -tmp1;
1278 : // derivative of cpositions
1279 0 : ddist_dcreference+=tmp1;
1280 : }
1281 : }
1282 :
1283 0 : if(!alEqDis) for(unsigned iat=0; iat<n; iat++)derivatives[iat]=prefactor*(derivatives[iat]+ddist_dcreference*align[iat]);
1284 :
1285 0 : return derivatives;
1286 : }
1287 :
1288 :
1289 :
1290 : /*
1291 : This below is the derivative of the rotation matrix that aligns the reference onto the positions
1292 : respect to positions
1293 : note that the this transformation overlap the reference onto position
1294 : if inverseTransform=true then aligns the positions onto reference
1295 : */
1296 4489 : Matrix<std::vector<Vector> > RMSDCoreData::getDRotationDPositions( bool inverseTransform ) {
1297 8978 : const unsigned n=static_cast<unsigned int>(reference.size());
1298 4489 : plumed_massert(!retrieve_only_rotation,"You used only_rotation=true in doCoreCalc therefore you cannot retrieve this information now");
1299 4489 : if(!isInitialized)plumed_merror("getDRotationDPosition to initialize the coreData first!");
1300 : Matrix<std::vector<Vector> > DRotDPos=Matrix<std::vector<Vector> >(3,3);
1301 : // remember drotation_drr01 is Tensor drotation_drr01[3][3]
1302 : // (3x3 rot) (3x3 components of rr01)
1303 4489 : std::vector<Vector> v(n);
1304 4489 : Vector csum;
1305 : // these below could probably be calculated in the main routine
1306 4489 : Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions;
1307 4489 : Vector cr; cr.zero(); if(!creference_is_removed)cr=creference;
1308 203764 : for(unsigned iat=0; iat<n; iat++) csum+=(reference[iat]-cr)*align[iat];
1309 270189 : for(unsigned iat=0; iat<n; iat++) v[iat]=(reference[iat]-cr-csum)*align[iat];
1310 31423 : for(unsigned a=0; a<3; a++) {
1311 94269 : for(unsigned b=0; b<3; b++) {
1312 40401 : if(inverseTransform) {
1313 40401 : DRotDPos[b][a].resize(n);
1314 1236051 : for(unsigned iat=0; iat<n; iat++) {
1315 2391300 : DRotDPos[b][a][iat]=matmul(drotation_drr01[a][b],v[iat]);
1316 : }
1317 : } else {
1318 0 : DRotDPos[a][b].resize(n);
1319 0 : for(unsigned iat=0; iat<n; iat++) {
1320 0 : DRotDPos[a][b][iat]=matmul(drotation_drr01[a][b],v[iat]);
1321 : }
1322 : }
1323 : }
1324 : }
1325 4489 : return DRotDPos;
1326 : }
1327 :
1328 : /*
1329 : This below is the derivative of the rotation matrix that aligns the reference onto the positions
1330 : respect to reference
1331 : note that the this transformation overlap the reference onto position
1332 : if inverseTransform=true then aligns the positions onto reference
1333 : */
1334 0 : Matrix<std::vector<Vector> > RMSDCoreData::getDRotationDReference( bool inverseTransform ) {
1335 0 : const unsigned n=static_cast<unsigned int>(reference.size());
1336 0 : plumed_massert(!retrieve_only_rotation,"You used only_rotation=true in doCoreCalc therefore you cannot retrieve this information now");
1337 0 : if(!isInitialized)plumed_merror("getDRotationDPositions to initialize the coreData first!");
1338 : Matrix<std::vector<Vector> > DRotDRef=Matrix<std::vector<Vector> >(3,3);
1339 : // remember drotation_drr01 is Tensor drotation_drr01[3][3]
1340 : // (3x3 rot) (3x3 components of rr01)
1341 0 : std::vector<Vector> v(n);
1342 0 : Vector csum;
1343 : // these below could probably be calculated in the main routine
1344 0 : Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions;
1345 0 : Vector cr; cr.zero(); if(!creference_is_removed)cr=creference;
1346 0 : for(unsigned iat=0; iat<n; iat++) csum+=(positions[iat]-cp)*align[iat];
1347 0 : for(unsigned iat=0; iat<n; iat++) v[iat]=(positions[iat]-cp-csum)*align[iat];
1348 :
1349 0 : for(unsigned a=0; a<3; a++) {
1350 0 : for(unsigned b=0; b<3; b++) {
1351 0 : Tensor t_drotation_drr01=drotation_drr01[a][b].transpose();
1352 0 : if(inverseTransform) {
1353 0 : DRotDRef[b][a].resize(n);
1354 0 : for(unsigned iat=0; iat<n; iat++) {
1355 0 : DRotDRef[b][a][iat]=matmul(t_drotation_drr01,v[iat]);
1356 : }
1357 : } else {
1358 0 : DRotDRef[a][b].resize(n);
1359 0 : for(unsigned iat=0; iat<n; iat++) {
1360 0 : DRotDRef[a][b][iat]=matmul(t_drotation_drr01,v[iat]);
1361 : }
1362 : }
1363 : }
1364 : }
1365 0 : return DRotDRef;
1366 : }
1367 :
1368 :
1369 0 : std::vector<Vector> RMSDCoreData::getAlignedReferenceToPositions() {
1370 : std::vector<Vector> alignedref;
1371 0 : const unsigned n=static_cast<unsigned int>(reference.size());
1372 0 : alignedref.resize(n);
1373 0 : if(!isInitialized)plumed_merror("getAlignedReferenceToPostions needs to initialize the coreData first!");
1374 : // avoid to calculate matrix element but use the sum of what you have
1375 0 : Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions;
1376 0 : for(unsigned iat=0; iat<n; iat++)alignedref[iat]=-d[iat]+positions[iat]-cp;
1377 0 : return alignedref;
1378 : }
1379 4441 : std::vector<Vector> RMSDCoreData::getAlignedPositionsToReference() {
1380 : std::vector<Vector> alignedpos;
1381 4441 : if(!isInitialized)plumed_merror("getAlignedPostionsToReference needs to initialize the coreData first!");
1382 8882 : const unsigned n=static_cast<unsigned int>(positions.size());
1383 4441 : alignedpos.resize(n);
1384 4441 : Vector cp; cp.zero(); if(!cpositions_is_removed)cp=cpositions;
1385 : // avoid to calculate matrix element but use the sum of what you have
1386 202996 : for(unsigned iat=0; iat<n; iat++)alignedpos[iat]=matmul(rotation.transpose(),positions[iat]-cp);
1387 4441 : return alignedpos;
1388 : }
1389 :
1390 :
1391 4489 : std::vector<Vector> RMSDCoreData::getCenteredPositions() {
1392 : std::vector<Vector> centeredpos;
1393 8978 : const unsigned n=static_cast<unsigned int>(reference.size());
1394 4489 : centeredpos.resize(n);
1395 4489 : if(!isInitialized)plumed_merror("getCenteredPositions needs to initialize the coreData first!");
1396 : // avoid to calculate matrix element but use the sum of what you have
1397 137339 : for(unsigned iat=0; iat<n; iat++)centeredpos[iat]=positions[iat]-cpositions;
1398 4489 : return centeredpos;
1399 : }
1400 :
1401 4441 : std::vector<Vector> RMSDCoreData::getCenteredReference() {
1402 : std::vector<Vector> centeredref;
1403 8882 : const unsigned n=static_cast<unsigned int>(reference.size());
1404 4441 : centeredref.resize(n);
1405 4441 : if(!isInitialized)plumed_merror("getCenteredReference needs to initialize the coreData first!");
1406 : // avoid to calculate matrix element but use the sum of what you have
1407 4441 : Vector cr; cr.zero(); if(!creference_is_removed)cr=creference;
1408 136811 : for(unsigned iat=0; iat<n; iat++)centeredref[iat]=reference[iat]-cr;
1409 4441 : return centeredref;
1410 : }
1411 :
1412 :
1413 48 : Vector RMSDCoreData::getPositionsCenter() {
1414 48 : if(!isInitialized)plumed_merror("getCenteredPositions needs to initialize the coreData first!");
1415 48 : return cpositions;
1416 : }
1417 :
1418 0 : Vector RMSDCoreData::getReferenceCenter() {
1419 0 : if(!isInitialized)plumed_merror("getCenteredPositions needs to initialize the coreData first!");
1420 0 : return creference;
1421 : }
1422 :
1423 1764 : Tensor RMSDCoreData::getRotationMatrixReferenceToPositions() {
1424 1764 : if(!isInitialized)plumed_merror("getRotationMatrixReferenceToPositions needs to initialize the coreData first!");
1425 1764 : return rotation;
1426 : }
1427 :
1428 4489 : Tensor RMSDCoreData::getRotationMatrixPositionsToReference() {
1429 4489 : if(!isInitialized)plumed_merror("getRotationMatrixReferenceToPositions needs to initialize the coreData first!");
1430 4489 : return rotation.transpose();
1431 : }
1432 :
1433 1092 : const std::array<std::array<Tensor,3>,3> & RMSDCoreData::getDRotationDRr01() const {
1434 1092 : if(!isInitialized)plumed_merror("getDRotationDRr01 needs to initialize the coreData first!");
1435 1092 : return drotation_drr01;
1436 : }
1437 :
1438 :
1439 :
1440 : template double RMSD::optimalAlignment<true,true>(const std::vector<double> & align,
1441 : const std::vector<double> & displace,
1442 : const std::vector<Vector> & positions,
1443 : const std::vector<Vector> & reference,
1444 : std::vector<Vector> & derivatives, bool squared)const;
1445 : template double RMSD::optimalAlignment<true,false>(const std::vector<double> & align,
1446 : const std::vector<double> & displace,
1447 : const std::vector<Vector> & positions,
1448 : const std::vector<Vector> & reference,
1449 : std::vector<Vector> & derivatives, bool squared)const;
1450 : template double RMSD::optimalAlignment<false,true>(const std::vector<double> & align,
1451 : const std::vector<double> & displace,
1452 : const std::vector<Vector> & positions,
1453 : const std::vector<Vector> & reference,
1454 : std::vector<Vector> & derivatives, bool squared)const;
1455 : template double RMSD::optimalAlignment<false,false>(const std::vector<double> & align,
1456 : const std::vector<double> & displace,
1457 : const std::vector<Vector> & positions,
1458 : const std::vector<Vector> & reference,
1459 : std::vector<Vector> & derivatives, bool squared)const;
1460 :
1461 :
1462 :
1463 4839 : }
|