Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2013-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 "MatrixTimesVectorBase.h" 23 : #include "core/ActionRegister.h" 24 : #include "core/ActionShortcut.h" 25 : #include "core/ActionWithArguments.h" 26 : #include "core/PlumedMain.h" 27 : #include "core/ActionSet.h" 28 : 29 : //+PLUMEDOC MCOLVAR MATRIX_VECTOR_PRODUCT 30 : /* 31 : Calculate the product of the matrix and the vector 32 : 33 : Thiis action allows you to [multiply](https://en.wikipedia.org/wiki/Matrix_multiplication) a matrix and a vector together. 34 : This action is primarily used to calculate coordination numbers and symmetry functions, which is what is done by the example below: 35 : 36 : ```plumed 37 : c1: CONTACT_MATRIX GROUP=1-7 SWITCH={RATIONAL R_0=2.6 NN=6 MM=12} 38 : ones: ONES SIZE=7 39 : cc: MATRIX_VECTOR_PRODUCT ARG=c1,ones 40 : PRINT ARG=cc FILE=colvar 41 : ``` 42 : 43 : Notice that you can use this action to multiply multiple matrices by a single vector as shown below: 44 : 45 : ```plumed 46 : c1: CONTACT_MATRIX COMPONENTS GROUP=1-7 SWITCH={RATIONAL R_0=2.6 NN=6 MM=12 D_MAX=10.0} 47 : ones: ONES SIZE=7 48 : cc: MATRIX_VECTOR_PRODUCT ARG=c1.x,c1.y,c1.z,ones 49 : PRINT ARG=cc.x,cc.y,cc.z FILE=colvar 50 : ``` 51 : 52 : Notice that if you use this options all the input matrices must have the same sparsity pattern. This feature 53 : was implemented in order to making caluclating Steinhardt parameters such as [Q6](Q6.md) straightforward. 54 : 55 : You can also multiply a single matrix by multiple vectors: 56 : 57 : ```plumed 58 : c1: CONTACT_MATRIX GROUP=1-7 SWITCH={RATIONAL R_0=2.6 NN=6 MM=12 D_MAX=10.0} 59 : ones: ONES SIZE=7 60 : twos: CONSTANT VALUES=1,2,3,4,5,6,7 61 : cc: MATRIX_VECTOR_PRODUCT ARG=c1,ones,twos 62 : PRINT ARG=cc.ones,cc.twos FILE=colvar 63 : ``` 64 : 65 : This feature was implemented to make calculating local averages of the Steinhard parameters straightforward. 66 : 67 : */ 68 : //+ENDPLUMEDOC 69 : 70 : namespace PLMD { 71 : namespace matrixtools { 72 : 73 : class MatrixTimesVector : public ActionShortcut { 74 : public: 75 : static void registerKeywords( Keywords& keys ); 76 : explicit MatrixTimesVector(const ActionOptions&ao); 77 : }; 78 : 79 : PLUMED_REGISTER_ACTION(MatrixTimesVector,"MATRIX_VECTOR_PRODUCT") 80 : 81 687 : void MatrixTimesVector::registerKeywords( Keywords& keys ) { 82 687 : ActionShortcut::registerKeywords(keys); 83 : // registerLocalKeywords() does not depend on the CV type. Instantiate the 84 : // template with a concrete CV that provides performTask()/getAdditionalIndices() 85 : // so that the class is well-formed: MSVC instantiates the member bodies 86 : // eagerly and would otherwise require those members from PLMD::Vector. 87 687 : MatrixTimesVectorBase<MatrixTimesVectorRowSums<double>>::registerLocalKeywords( keys ); 88 687 : keys.addActionNameSuffix("_ROWSUMS"); 89 687 : keys.addActionNameSuffix("_ROWSUMSACC"); 90 687 : keys.addActionNameSuffix("_PROPER"); 91 1374 : keys.addActionNameSuffix("_PROPERACC"); 92 : 93 687 : if(!keys.exists("USEGPU")) { 94 0 : keys.addFlag("USEGPU",false,"run this calculation on the GPU"); 95 0 : keys.addLinkInDocForFlag("USEGPU","plugin_openaccPTM.md.md"); 96 : } 97 687 : } 98 : 99 395 : MatrixTimesVector::MatrixTimesVector( const ActionOptions& ao): 100 : Action(ao), 101 395 : ActionShortcut(ao) { 102 395 : std::vector<std::string> args; 103 395 : parseVector("ARG",args); 104 395 : std::vector<Value*> myargs; 105 395 : ActionWithArguments::interpretArgumentList( args, plumed.getActionSet(), this, myargs ); 106 395 : std::string usegpustr=" "; 107 : { 108 : bool usegpu; 109 395 : parseFlag("USEGPU",usegpu); 110 395 : if( usegpu ) { 111 : usegpustr = "ACC "; 112 : } 113 : } 114 : unsigned nvectors=0, nmatrices=0; 115 2057 : for(unsigned i=0; i<myargs.size(); ++i) { 116 1662 : if( myargs[i]->hasDerivatives() ) { 117 0 : error("arguments should be vectors or matrices"); 118 : } 119 1662 : if( myargs[i]->getRank()<=1 ) { 120 580 : nvectors++; 121 : } 122 1662 : if( myargs[i]->getRank()==2 ) { 123 1082 : nmatrices++; 124 : } 125 : } 126 395 : std::string argstr = args[0]; 127 975 : for(unsigned i=1; i<args.size(); ++i) { 128 1160 : argstr += "," + args[i]; 129 : } 130 : 131 : bool sumrows=false; 132 395 : if( nvectors==1 ) { 133 386 : unsigned n = myargs.size()-1; 134 1459 : for(unsigned i=0; i<n; ++i) { 135 1073 : if( myargs[i]->getRank()!=2 || myargs[i]->hasDerivatives() ) { 136 0 : error("all arguments other than last argument should be matrices"); 137 : } 138 1073 : if( myargs[n]->getRank()==0 ) { 139 1 : if( myargs[i]->getShape()[1]!=1 ) { 140 0 : error("number of columns in input matrix does not equal number of elements in vector"); 141 : } 142 1072 : } else if( myargs[i]->getShape()[1]!=myargs[n]->getShape()[0] ) { 143 : std::string str_nmat, str_nvec; 144 0 : Tools::convert( myargs[i]->getShape()[1], str_nmat); 145 0 : Tools::convert( myargs[n]->getShape()[0], str_nvec ); 146 0 : error("number of columns in input matrix is " + str_nmat + " which does not equal number of elements in vector, which is " + str_nvec); 147 : } 148 : } 149 386 : if( myargs[n]->getRank()>0 ) { 150 385 : if( myargs[n]->getRank()!=1 || myargs[n]->hasDerivatives() ) { 151 0 : error("last argument to this action should be a vector"); 152 : } 153 : } 154 386 : if( (myargs[n]->getPntrToAction())->getName()=="CONSTANT" ) { 155 : sumrows=true; 156 347 : if( myargs[n]->getRank()==0 ) { 157 1 : if( fabs( myargs[n]->get() - 1.0 )>epsilon ) { 158 : sumrows = false; 159 : } 160 : } else { 161 204311 : for(unsigned i=0; i<myargs[n]->getShape()[0]; ++i) { 162 203973 : if( fabs( myargs[n]->get(i) - 1.0 )>epsilon ) { 163 : sumrows=false; 164 : break; 165 : } 166 : } 167 : } 168 : } 169 346 : if( sumrows ) { 170 678 : readInputLine( getShortcutLabel() + ": MATRIX_VECTOR_PRODUCT_ROWSUMS"+usegpustr 171 1356 : +"ARG="+ argstr + " " + convertInputLineToString() ); 172 : } else { 173 94 : readInputLine( getShortcutLabel() + ": MATRIX_VECTOR_PRODUCT_PROPER"+usegpustr 174 188 : +"ARG="+ argstr + " " + convertInputLineToString() ); 175 : } 176 9 : } else if( nmatrices==1 ) { 177 9 : if( myargs[0]->getRank()!=2 || myargs[0]->hasDerivatives() ) { 178 0 : error("first argument to this action should be a matrix"); 179 : } 180 203 : for(unsigned i=1; i<myargs.size(); ++i) { 181 194 : if( myargs[i]->getRank()>1 || myargs[i]->hasDerivatives() ) { 182 0 : error("all arguments other than first argument should be vectors"); 183 : } 184 194 : if( myargs[i]->getRank()==0 ) { 185 0 : if( myargs[0]->getShape()[1]!=1 ) { 186 0 : error("number of columns in input matrix does not equal number of elements in vector"); 187 : } 188 194 : } else if( myargs[0]->getShape()[1]!=myargs[i]->getShape()[0] ) { 189 0 : error("number of columns in input matrix does not equal number of elements in vector"); 190 : } 191 : } 192 18 : readInputLine( getShortcutLabel() + ": MATRIX_VECTOR_PRODUCT_PROPER"+usegpustr 193 36 : +"ARG="+ argstr + " " + convertInputLineToString() ); 194 : } else { 195 0 : error("You should either have one vector or one matrix in input"); 196 : } 197 395 : } 198 : 199 : } 200 : }