Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2016,2017 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/ActionWithVector.h" 23 : #include "core/ActionRegister.h" 24 : #include "core/ActionSet.h" 25 : #include "PathProjectionCalculator.h" 26 : 27 : //+PLUMEDOC COLVAR GEOMETRIC_PATH 28 : /* 29 : Distance along and from a path calculated using geometric formulas 30 : 31 : \par Examples 32 : 33 : */ 34 : //+ENDPLUMEDOC 35 : 36 : namespace PLMD { 37 : namespace mapping { 38 : 39 : class GeometricPath : public ActionWithVector { 40 : private: 41 : PathProjectionCalculator path_projector; 42 : public: 43 : static void registerKeywords(Keywords& keys); 44 : explicit GeometricPath(const ActionOptions&); 45 : unsigned getNumberOfDerivatives() override ; 46 : void calculate() override ; 47 0 : void performTask( const unsigned& current, MultiValue& myvals ) const override { 48 0 : plumed_error(); 49 : } 50 : }; 51 : 52 : PLUMED_REGISTER_ACTION(GeometricPath,"GEOMETRIC_PATH") 53 : 54 10 : void GeometricPath::registerKeywords(Keywords& keys) { 55 10 : ActionWithVector::registerKeywords(keys); 56 10 : PathProjectionCalculator::registerKeywords(keys); 57 20 : keys.addInputKeyword("compulsory","PROPERTY","vector","the label of a value that contains the coordinates we are projecting these points onto"); 58 20 : keys.addOutputComponent("s","default","scalar","the position on the path"); 59 20 : keys.addOutputComponent("z","default","scalar","the distance from the path"); 60 10 : keys.needsAction("GEOMETRIC_PATH"); 61 10 : keys.needsAction("PDB2CONSTANT"); 62 10 : } 63 : 64 4 : GeometricPath::GeometricPath(const ActionOptions&ao): 65 : Action(ao), 66 : ActionWithVector(ao), 67 4 : path_projector(this) { 68 4 : plumed_assert( !actionInChain() ); 69 : // Get the coordinates in the low dimensional space 70 : std::vector<std::string> pcoord; 71 8 : parseVector("PROPERTY", pcoord ); 72 : std::vector<Value*> theprop; 73 4 : ActionWithArguments::interpretArgumentList( pcoord, plumed.getActionSet(), this, theprop ); 74 4 : if( theprop.size()!=1 ) { 75 0 : error("did not find property to project on"); 76 : } 77 4 : if( theprop[0]->getNumberOfValues()!=getPntrToArgument(0)->getShape()[0] ) { 78 0 : error("mismatch between number of frames and property of interest"); 79 : } 80 4 : log.printf(" projecting onto : %s \n", theprop[0]->getName().c_str() ); 81 4 : std::vector<Value*> args( getArguments() ); 82 4 : args.push_back( theprop[0] ); 83 4 : requestArguments( args ); 84 : // Create the values to store the output 85 8 : addComponentWithDerivatives("s"); 86 8 : componentIsNotPeriodic("s"); 87 8 : addComponentWithDerivatives("z"); 88 8 : componentIsNotPeriodic("z"); 89 4 : } 90 : 91 1677 : unsigned GeometricPath::getNumberOfDerivatives() { 92 1677 : return getPntrToArgument(0)->getShape()[0]*getPntrToArgument(0)->getShape()[1] + getPntrToArgument(1)->getShape()[0]; 93 : } 94 : 95 1665 : void GeometricPath::calculate() { 96 1665 : unsigned k=0, iclose1=0, iclose2=0; 97 : double v1v1=0, v3v3=0; 98 1665 : unsigned nrows = getPntrToArgument(0)->getShape()[0]; 99 1665 : unsigned ncols = getPntrToArgument(0)->getShape()[1]; 100 79201 : for(unsigned i=0; i<nrows; ++i) { 101 : double dist = 0; 102 1814580 : for(unsigned j=0; j<ncols; ++j) { 103 1737044 : double tmp = getPntrToArgument(0)->get(k); 104 1737044 : dist += tmp*tmp; 105 1737044 : k++; 106 : } 107 77536 : if( i==0 ) { 108 : v1v1 = dist; 109 1665 : iclose1 = 0; 110 75871 : } else if( dist<v1v1 ) { 111 : v3v3=v1v1; 112 : v1v1=dist; 113 30300 : iclose2=iclose1; 114 30300 : iclose1=i; 115 45571 : } else if( i==1 ) { 116 : v3v3=dist; 117 327 : iclose2=1; 118 45244 : } else if( dist<v3v3 ) { 119 : v3v3=dist; 120 1325 : iclose2=i; 121 : } 122 : } 123 : // And find third closest point 124 1665 : int isign = iclose1 - iclose2; 125 : if( isign>1 ) { 126 : isign=1; 127 : } else if( isign<-1 ) { 128 : isign=-1; 129 : } 130 1665 : int iclose3 = iclose1 + isign; 131 1665 : unsigned ifrom=iclose1, ito=iclose3; 132 1665 : if( iclose3<0 || iclose3>=nrows ) { 133 31 : ifrom=iclose2; 134 31 : ito=iclose1; 135 : } 136 : 137 : // And calculate projection of vector connecting current point to closest frame on vector connecting nearest two frames 138 : std::vector<double> displace; 139 1665 : path_projector.getDisplaceVector( ifrom, ito, displace ); 140 : double v2v2=0, v1v2=0; 141 1665 : k=ncols*iclose1; 142 42661 : for(unsigned i=0; i<displace.size(); ++i) { 143 40996 : v2v2 += displace[i]*displace[i]; 144 40996 : v1v2 += displace[i]*getPntrToArgument(0)->get(k+i); 145 : } 146 : 147 : // This computes s value 148 1665 : double spacing = getPntrToArgument(1)->get(iclose1) - getPntrToArgument(1)->get(iclose2); 149 1665 : double root = sqrt( v1v2*v1v2 - v2v2 * ( v1v1 - v3v3) ); 150 1665 : double dx = 0.5 * ( (root + v1v2) / v2v2 - 1.); 151 1665 : double path_s = getPntrToArgument(1)->get(iclose1) + spacing * dx; 152 1665 : Value* sp = getPntrToComponent(0); 153 : sp->set( path_s ); 154 1665 : if( !doNotCalculateDerivatives() ) { 155 23478 : for(unsigned i=0; i<ncols; ++i) { 156 22386 : sp->addDerivative( ncols*iclose1 + i, 0.5*spacing*(v1v2*displace[i]/v2v2 - getPntrToArgument(0)->get(ncols*iclose1 + i))/root + 0.5*spacing*displace[i]/v2v2 ); 157 22386 : sp->addDerivative( ncols*iclose2 + i, 0.5*spacing*getPntrToArgument(0)->get(ncols*iclose2 + i)/root ); 158 : } 159 : } 160 : 161 : // This computes z value 162 1665 : path_projector.getDisplaceVector( iclose2, iclose1, displace ); 163 : double v4v4=0, proj=0; 164 1665 : k=ncols*iclose1; 165 42661 : for(unsigned i=0; i<displace.size(); ++i) { 166 40996 : v4v4 += displace[i]*displace[i]; 167 40996 : proj += displace[i]*getPntrToArgument(0)->get(k+i); 168 : } 169 1665 : double path_z = v1v1 + dx*dx*v4v4 - 2*dx*proj; 170 1665 : path_z = sqrt(path_z); 171 1665 : Value* zp = getPntrToComponent(1); 172 : zp->set( path_z ); 173 1665 : if( !doNotCalculateDerivatives() ) { 174 23478 : for(unsigned i=0; i<ncols; ++i) { 175 22386 : zp->addDerivative( ncols*iclose1 + i, (1/path_z)*(getPntrToArgument(0)->get(ncols*iclose1 + i) + 176 22386 : (v4v4*dx-proj)*sp->getDerivative(ncols*iclose1 + i)/spacing - 177 22386 : dx*displace[i]) ); 178 22386 : zp->addDerivative( ncols*iclose2 + i, (v4v4*dx-proj)*sp->getDerivative(ncols*iclose2 + i)/(path_z*spacing) ); 179 : } 180 : } 181 1665 : } 182 : 183 : } 184 : }