Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2016-2018 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/ActionWithArguments.h" 25 : #include "core/ActionRegister.h" 26 : #include "tools/Matrix.h" 27 : #include "PathProjectionCalculator.h" 28 : 29 : //+PLUMEDOC ANALYSIS AVERAGE_PATH_DISPLACEMENT 30 : /* 31 : Accumulate the distances between the reference frames in the paths and the configurations visited 32 : 33 : \par Examples 34 : 35 : */ 36 : //+ENDPLUMEDOC 37 : 38 : namespace PLMD { 39 : namespace mapping { 40 : 41 : class PathDisplacements : public ActionWithValue, public ActionPilot, public ActionWithArguments { 42 : private: 43 : bool clearnextstep; 44 : unsigned clearstride; 45 : double fadefact; 46 : std::vector<double> wsum, displace_v; 47 : Matrix<double> displacements; 48 : PathProjectionCalculator path_projector; 49 : public: 50 : static void registerKeywords( Keywords& keys ); 51 : explicit PathDisplacements(const ActionOptions&); 52 : unsigned getNumberOfDerivatives(); 53 573 : void clearDerivatives( const bool& force=false ) {} 54 573 : void calculate() {} 55 573 : void apply() {} 56 : void update(); 57 : }; 58 : 59 : PLUMED_REGISTER_ACTION(PathDisplacements,"AVERAGE_PATH_DISPLACEMENT") 60 : 61 6 : void PathDisplacements::registerKeywords( Keywords& keys ) { 62 6 : Action::registerKeywords( keys ); ActionWithValue::registerKeywords( keys ); ActionPilot::registerKeywords( keys ); 63 6 : ActionWithArguments::registerKeywords( keys ); PathProjectionCalculator::registerKeywords( keys ); 64 12 : keys.add("compulsory","STRIDE","1","the frequency with which the average displacements should be collected and added to the average displacements"); 65 12 : keys.add("compulsory","HALFLIFE","-1","the number of MD steps after which a previously measured path distance weighs only 50 percent in the average. This option may increase convergence by allowing to forget the memory of a bad initial guess path. The default is to set this to infinity"); 66 12 : keys.add("compulsory","CLEAR","0","the frequency with which to clear all the accumulated data. The default value " 67 : "of 0 implies that all the data will be used and that the grid will never be cleared"); 68 12 : keys.setValueDescription("matrix","matrix containing the average displacement between the trajectory and each of the landmarks that makes up the path"); 69 6 : } 70 : 71 2 : PathDisplacements::PathDisplacements(const ActionOptions& ao): 72 : Action(ao), 73 : ActionWithValue(ao), 74 : ActionPilot(ao), 75 : ActionWithArguments(ao), 76 2 : clearnextstep(false), 77 2 : path_projector(this) 78 : { 79 : // Read in clear instructions 80 2 : parse("CLEAR",clearstride); 81 2 : if( clearstride>0 ) { 82 2 : if( clearstride%getStride()!=0 ) error("CLEAR parameter must be a multiple of STRIDE"); 83 2 : log.printf(" clearing average every %u steps \n",clearstride); 84 : } 85 2 : double halflife; parse("HALFLIFE",halflife); 86 2 : log.printf(" weight of contribution to frame halves every %f steps \n",halflife); 87 2 : if( halflife<0 ) fadefact=1.0; 88 0 : else fadefact = exp( -0.693147180559945 / static_cast<double>(halflife) ); 89 : // Now create the weights vector and displacements matrix 90 2 : unsigned nrows = getPntrToArgument(0)->getShape()[0]; 91 2 : unsigned ncols = getPntrToArgument(0)->getShape()[1]; 92 2 : wsum.resize( nrows ); displacements.resize( nrows, ncols ); 93 64 : for(unsigned i=0; i<nrows; ++i) { 94 1740 : wsum[i]=0; for(unsigned j=0; j<ncols; ++j) displacements(i,j)=0; 95 : } 96 : // Add bibliography 97 4 : log<<" Bibliography "<<plumed.cite("Diaz Leines and Ensing, Phys. Rev. Lett. 109, 020601 (2012)")<<"\n"; 98 : // And create a value to hold the displacements 99 2 : std::vector<unsigned> shape(2); shape[0]=nrows; shape[1]=ncols; 100 2 : addValue( shape ); setNotPeriodic(); 101 2 : getPntrToComponent(0)->buildDataStore(); 102 2 : getPntrToComponent(0)->reshapeMatrixStore( shape[1] ); 103 2 : } 104 : 105 0 : unsigned PathDisplacements::getNumberOfDerivatives() { 106 0 : return 0; 107 : } 108 : 109 573 : void PathDisplacements::update() { 110 573 : unsigned nrows = getPntrToArgument(0)->getShape()[0]; 111 573 : unsigned ncols = getPntrToArgument(0)->getShape()[1]; 112 : 113 573 : if( clearnextstep ) { 114 : unsigned k=0; 115 1010 : for(unsigned i=0; i<nrows; ++i) { 116 38700 : for(unsigned j=0; j<ncols; ++j) { displacements(i,j)=0; getPntrToComponent(0)->set(k,0); k++; } 117 : } 118 24 : clearnextstep=false; 119 : } 120 : 121 : unsigned k=0, iclose1=0, iclose2=0; double v1v1=0, v3v3=0; 122 22417 : for(unsigned i=0; i<nrows; ++i) { 123 : double dist = 0; 124 799020 : for(unsigned j=0; j<ncols; ++j) { 125 777176 : double tmp = getPntrToArgument(0)->get(k); 126 777176 : dist += tmp*tmp; k++; 127 : } 128 21844 : if( i==0 ) { v1v1 = dist; iclose1 = 0; } 129 21271 : else if( dist<v1v1 ) { v3v3=v1v1; v1v1=dist; iclose2=iclose1; iclose1=i; } 130 10991 : else if( i==1 ) { v3v3=dist; iclose2=1; } 131 10991 : else if( dist<v3v3 ) { v3v3=dist; iclose2=i; } 132 : } 133 : // And find third closest point 134 573 : int isign = iclose1 - iclose2; 135 : if( isign>1 ) isign=1; else if( isign<-1 ) isign=-1; 136 573 : int iclose3 = iclose1 + isign; 137 573 : unsigned ifrom=iclose1, ito=iclose3; if( iclose3<0 || iclose3>=nrows ) { ifrom=iclose2; ito=iclose1; } 138 : 139 : // Calculate the dot product of v1 with v2 140 573 : path_projector.getDisplaceVector( ifrom, ito, displace_v ); 141 573 : double v2v2=0, v1v2=0; unsigned kclose1 = iclose1*ncols; 142 19183 : for(unsigned i=0; i<displace_v.size(); ++i) { v2v2 += displace_v[i]*displace_v[i]; v1v2 += displace_v[i]*getPntrToArgument(0)->get(kclose1+i); } 143 : 144 573 : double root = sqrt( v1v2*v1v2 - v2v2 * ( v1v1 - v3v3) ); 145 573 : double dx = 0.5 * ( (root + v1v2) / v2v2 - 1.); 146 573 : double weight2 = -1.* dx; double weight1 = 1.0 + dx; 147 573 : if( weight1>1.0 ) { 148 : weight1=1.0; weight2=0.0; 149 573 : } else if( weight2>1.0 ) { 150 : weight1=0.0; weight2=1.0; 151 : } 152 : 153 : // Accumulate displacements for path 154 19183 : for(unsigned i=0; i<ncols; ++i) { 155 18610 : double displace = getPntrToArgument(0)->get(kclose1+i) - dx*displace_v[i]; 156 18610 : displacements(iclose1,i) += weight1 * displace; displacements(iclose2,i) += weight2 * displace; 157 : } 158 : 159 : // Update weight accumulators 160 573 : wsum[iclose1] *= fadefact; wsum[iclose2] *= fadefact; 161 573 : wsum[iclose1] += weight1; wsum[iclose2] += weight2; 162 : 163 : // Update numbers in values 164 573 : if( wsum[iclose1] > epsilon ) { 165 19183 : for(unsigned i=0; i<ncols; ++i) getPntrToComponent(0)->set( kclose1+i, displacements(iclose1,i) / wsum[iclose1] ); 166 : } 167 573 : if( wsum[iclose2] > epsilon ) { 168 573 : unsigned kclose2 = iclose2*ncols; 169 19183 : for(unsigned i=0; i<ncols; ++i) getPntrToComponent(0)->set( kclose2+i, displacements(iclose2,i) / wsum[iclose2] ); 170 : } 171 : 172 : // Clear if required 173 573 : if( (getStep()>0 && clearstride>0 && getStep()%clearstride==0) ) clearnextstep=true; 174 573 : } 175 : 176 : } 177 : }