LCOV - code coverage report
Current view: top level - tools - ERMSD.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 121 123 98.4 %
Date: 2026-11-12 10:48:31 Functions: 4 5 80.0 %

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

Generated by: LCOV version 1.16