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