LCOV - code coverage report
Current view: top level - mapping - PathReparameterization.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 90 94 95.7 %
Date: 2024-10-18 14:00:25 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2016-2020 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 "core/ActionWithValue.h"
      23             : #include "core/ActionPilot.h"
      24             : #include "core/ActionRegister.h"
      25             : #include "core/PlumedMain.h"
      26             : #include "core/ActionSet.h"
      27             : #include "tools/Pbc.h"
      28             : #include "tools/Matrix.h"
      29             : #include "PathProjectionCalculator.h"
      30             : 
      31             : //+PLUMEDOC ANALYSIS REPARAMETERIZE_PATH
      32             : /*
      33             : Take an input path with frames that are not equally spaced and make the frames equally spaced
      34             : 
      35             : \par Examples
      36             : 
      37             : */
      38             : //+ENDPLUMEDOC
      39             : 
      40             : namespace PLMD {
      41             : namespace mapping {
      42             : 
      43             : class PathReparameterization : public ActionPilot {
      44             : private:
      45             : /// Number of cycles of the optimization algorithm to run
      46             :   unsigned maxcycles;
      47             : /// The points on the path to fix
      48             :   unsigned ifix1, ifix2;
      49             : /// Tolerance for the minimization algorithm
      50             :   double TOL;
      51             : /// Value containing ammount to displace each reference configuration by
      52             :   Value* displace_value;
      53             : /// The action for calculating the distances between the frames
      54             :   PathProjectionCalculator path_projector;
      55             : /// Used to store current spacing between frames in path
      56             :   std::vector<double> data, len, sumlen, sfrac;
      57             : ///
      58             :   bool loopEnd( const int& index, const int& end, const int& inc ) const ;
      59             : ///
      60             :   double computeSpacing( const unsigned& ifrom, const unsigned& ito );
      61             : ///
      62             :   void calcCurrentPathSpacings( const int& istart, const int& iend );
      63             : ///
      64             :   void reparameterizePart( const int& istart, const int& iend, const double& target );
      65             : public:
      66             :   static void registerKeywords( Keywords& keys );
      67             :   PathReparameterization(const ActionOptions&);
      68          27 :   void calculate() {}
      69          27 :   void apply() {}
      70             :   void update();
      71             : };
      72             : 
      73             : PLUMED_REGISTER_ACTION(PathReparameterization,"REPARAMETERIZE_PATH")
      74             : 
      75           8 : void PathReparameterization::registerKeywords( Keywords& keys ) {
      76           8 :   Action::registerKeywords( keys ); ActionPilot::registerKeywords( keys );
      77           8 :   PathProjectionCalculator::registerKeywords(keys);
      78          16 :   keys.add("compulsory","STRIDE","1","the frequency with which to reparameterize the path");
      79          16 :   keys.add("compulsory","FIXED","0","the frames in the path to fix");
      80          16 :   keys.add("compulsory","MAXCYLES","100","number of cycles of the algorithm to run");
      81          16 :   keys.add("compulsory","TOL","1E-4","the tolerance to use for the path reparameterization algorithm");
      82          16 :   keys.add("optional","DISPLACE_FRAMES","label of an action that tells us how to displace the frames.  These displacements are applied before "
      83             :            "running the reparameterization algorith");
      84           8 : }
      85             : 
      86           4 : PathReparameterization::PathReparameterization(const ActionOptions&ao):
      87             :   Action(ao),
      88             :   ActionPilot(ao),
      89           4 :   displace_value(NULL),
      90           4 :   path_projector(this)
      91             : {
      92           8 :   parse("MAXCYLES",maxcycles); parse("TOL",TOL);
      93           4 :   log.printf("  running till change is less than %f or until there have been %d optimization cycles \n", TOL, maxcycles);
      94           4 :   len.resize( path_projector.getNumberOfFrames()  ); sumlen.resize( path_projector.getNumberOfFrames() ); sfrac.resize( path_projector.getNumberOfFrames() );
      95           8 :   std::vector<unsigned> fixed; parseVector("FIXED",fixed);
      96           4 :   if( fixed.size()==1 ) {
      97           0 :     if( fixed[0]!=0 ) error("input to FIXED should be two integers");
      98           0 :     ifix1=0; ifix2=path_projector.getNumberOfFrames()-1;
      99           4 :   } else if( fixed.size()==2 ) {
     100           4 :     if( fixed[0]<1 || fixed[1]<1 || fixed[0]>path_projector.getNumberOfFrames() || fixed[1]>path_projector.getNumberOfFrames() ) {
     101           0 :       error("input to FIXED should be two numbers between 1 and the number of frames");
     102             :     }
     103           4 :     ifix1=fixed[0]-1; ifix2=fixed[1]-1;
     104           0 :   } else error("input to FIXED should be two integers");
     105           4 :   log.printf("  fixing frames %d and %d when reparameterizing \n", ifix1, ifix2 );
     106           8 :   std::string dframe; parse("DISPLACE_FRAMES",dframe);
     107           4 :   if( dframe.length()>0 ) {
     108           2 :     ActionWithValue* av = plumed.getActionSet().selectWithLabel<ActionWithValue*>( dframe );
     109           2 :     if( !av ) error("could not find action with label " + dframe + " specified to DISPLACE_FRAMES keyword in input file");
     110           2 :     if( av->getName()!="AVERAGE_PATH_DISPLACEMENT" ) error("displace object is not of correct type");
     111           2 :     displace_value = av->copyOutput(0);
     112             :   }
     113           4 : }
     114             : 
     115       11542 : bool PathReparameterization::loopEnd( const int& index, const int& end, const int& inc ) const {
     116       11542 :   if( inc>0 && index<end ) return false;
     117         428 :   else if( inc<0 && index>end ) return false;
     118             :   return true;
     119             : }
     120             : 
     121        4459 : double PathReparameterization::computeSpacing( const unsigned& ifrom, const unsigned& ito ) {
     122        4459 :   path_projector.getDisplaceVector( ifrom, ito, data );
     123      170534 :   double length=0; for(unsigned i=0; i<data.size(); ++i) length += data[i]*data[i];
     124        4459 :   return sqrt( length );
     125             : }
     126             : 
     127         139 : void PathReparameterization::calcCurrentPathSpacings( const int& istart, const int& iend ) {
     128             :   plumed_dbg_assert( istart<len.size() && iend<len.size() );
     129         139 :   len[istart] = sumlen[istart]=0;
     130             :   //printf("HELLO PATH SPACINGS ARE CURRENTLY \n");
     131             : 
     132             :   // Get the spacings given we can go forward and backwards
     133         139 :   int incr=1; if( istart>iend ) { incr=-1; }
     134             : 
     135        4598 :   for(int i=istart+incr; loopEnd(i,iend+incr,incr)==false; i+=incr) {
     136        4459 :     len[i] = computeSpacing( i-incr, i ); sumlen[i] = sumlen[i-incr] + len[i];
     137             :     //printf("FRAME %d TO FRAME %d EQUALS %f : %f \n",i-incr,i,len[i],sumlen[i] );
     138             :   }
     139         139 : }
     140             : 
     141          33 : void PathReparameterization::reparameterizePart( const int& istart, const int& iend, const double& target ) {
     142          33 :   calcCurrentPathSpacings( istart, iend ); unsigned cfin;
     143             :   // If a target separation is set we fix where we want the nodes
     144          33 :   int incr=1; if( istart>iend ) { incr=-1; }
     145             : 
     146          33 :   if( target>0 ) {
     147           6 :     if( iend>istart ) {
     148          19 :       for(unsigned i=istart; i<iend+1; ++i) sfrac[i] = target*(i-istart);
     149             :     } else {
     150          14 :       for(int i=istart-1; i>iend-1; --i) sfrac[i]=target*(istart-i);
     151             :     }
     152           6 :     cfin = iend+incr;
     153             :   } else {
     154          27 :     cfin = iend;
     155             :   }
     156             : 
     157          33 :   double prevsum=0.; Matrix<double> newmatrix( path_projector.getNumberOfFrames(), data.size() );
     158         139 :   for(unsigned iter=0; iter<maxcycles; ++iter) {
     159         139 :     if( fabs(sumlen[iend] - prevsum)<=TOL ) break ;
     160             :     prevsum = sumlen[iend];
     161             :     // If no target is set we redistribute length
     162         106 :     if( target<0 ) {
     163          94 :       plumed_assert( istart<iend );
     164          94 :       double dr = sumlen[iend] / static_cast<double>( iend - istart );
     165        3506 :       for(unsigned i=istart; i<iend; ++i) sfrac[i] = dr*(i-istart);
     166             :     }
     167             : 
     168             :     // Now compute positions of new nodes in path
     169        3472 :     for(int i=istart+incr; loopEnd(i,cfin,incr)==false; i+=incr) {
     170        3366 :       int k = istart;
     171       69429 :       while( !((sumlen[k] < sfrac[i]) && (sumlen[k+incr]>=sfrac[i])) ) {
     172       66069 :         k+=incr;
     173       66069 :         if( cfin==iend && k>= iend+1 ) plumed_merror("path reparameterization error");
     174       66069 :         else if( cfin==(iend+1) && k>=iend ) { k=iend-1; break; }
     175       66067 :         else if( cfin==(iend-1) && k<=iend ) { k=iend+1; break; }
     176             :       }
     177        3366 :       double dr = (sfrac[i]-sumlen[k])/len[k+incr];
     178             :       // Copy the reference configuration to the row of a matrix
     179        3366 :       path_projector.getReferenceConfiguration( k, data );
     180      129024 :       for(unsigned j=0; j<data.size(); ++j) newmatrix(i,j) = data[j];
     181        3366 :       path_projector.getDisplaceVector( k, k+incr, data );
     182             :       // Shift the reference configuration by this ammount
     183      129024 :       for(unsigned j=0; j<data.size(); ++j) newmatrix(i,j) += dr*data[j];
     184             :     }
     185             : 
     186             :     // Copy the positions of the new path to the new paths
     187        3472 :     for(int i=istart+incr; loopEnd(i,cfin,incr)==false; i+=incr) {
     188      129024 :       for(unsigned j=0; j<data.size(); ++j) data[j] = newmatrix(i,j);
     189        3366 :       path_projector.setReferenceConfiguration( i, data );
     190             :     }
     191             : 
     192             :     // Recompute the separations between frames
     193         106 :     calcCurrentPathSpacings( istart, iend );
     194             :   }
     195          33 : }
     196             : 
     197          29 : void PathReparameterization::update() {
     198             :   // We never run this on the first step
     199          29 :   if( getStep()==0 ) return ;
     200             : 
     201             :   // Shift the frames using the displacements
     202          27 :   if( displace_value ) {
     203        1031 :     for(unsigned i=0; i<path_projector.getNumberOfFrames(); ++i) {
     204        1006 :       if( i==ifix1 || i==ifix2 ) continue ;
     205             :       // Retrieve the current position of the frame
     206         956 :       path_projector.getReferenceConfiguration( i, data );
     207             :       // Shift using the averages accumulated in the action that accumulates the displacements
     208         956 :       unsigned kstart = i*data.size();
     209       36908 :       for(unsigned j=0; j<data.size(); ++j) data[j] += displace_value->get( kstart + j );
     210             :       // And now set the new position of the refernce frame
     211         956 :       path_projector.setReferenceConfiguration( i, data );
     212             :     }
     213             :   }
     214             : 
     215             :   // First reparameterize the part between the fixed frames
     216          27 :   reparameterizePart( ifix1, ifix2, -1.0 );
     217             : 
     218             :   // Get the separation between frames which we will use to set the remaining frames
     219          27 :   double target = sumlen[ifix2] / ( ifix2 - ifix1 );
     220             : 
     221             :   // And reparameterize the begining and end of the path
     222          27 :   if( ifix1>0 ) reparameterizePart( ifix1, 0, target );
     223          27 :   if( ifix2<(path_projector.getNumberOfFrames()-1) ) reparameterizePart( ifix2, path_projector.getNumberOfFrames()-1, target );
     224             :   // And update any RMSD objects that depend on input values
     225          27 :   path_projector.updateDepedentRMSDObjects();
     226             : }
     227             : 
     228             : }
     229             : }

Generated by: LCOV version 1.16