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