Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2015-2023 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 "ActionWithInputMatrix.h" 23 : #include "multicolvar/AtomValuePack.h" 24 : #include "AdjacencyMatrixVessel.h" 25 : #include "AdjacencyMatrixBase.h" 26 : #include "core/ActionRegister.h" 27 : #include "core/PlumedMain.h" 28 : #include "core/ActionSet.h" 29 : 30 : //+PLUMEDOC MATRIXF COLUMNSUMS 31 : /* 32 : Sum the columns of a contact matrix 33 : 34 : As discussed in the section of the manual on \ref contactmatrix a useful tool for developing complex collective variables is the notion of the 35 : so called adjacency matrix. An adjacency matrix is an \f$N \times N\f$ matrix in which the \f$i\f$th, \f$j\f$th element tells you whether 36 : or not the \f$i\f$th and \f$j\f$th atoms/molecules from a set of \f$N\f$ atoms/molecules are adjacent or not. This action allows you to calculate 37 : the sum of the columns in this adjacency matrix and to then calculate further functions of these quantities. 38 : 39 : \par Examples 40 : 41 : The first instruction in the following input file tells PLUMED to compute a \f$10 \times 10\f$ matrix in which the \f$ij\f$-element 42 : tells you whether atoms \f$i\f$ and \f$j\f$ are within 1.0 nm of each other. The numbers in each of this rows are then added together 43 : and the average value is computed. As such the following input provides an alternative method for calculating the coordination numbers 44 : of atoms 1 to 10. 45 : 46 : \plumedfile 47 : mat: CONTACT_MATRIX ATOMS=1-10 SWITCH={RATIONAL R_0=1.0} 48 : rsums: COLUMNSUMS MATRIX=mat MEAN 49 : PRINT ARG=rsums.* FILE=colvar 50 : \endplumedfile 51 : 52 : The following input demonstrates another way that an average coordination number can be computed. This input calculates the number of atoms 53 : with indices between 1 and 5 that are within the first coordination spheres of each of the atoms within indices between 6 and 15. The average 54 : coordination number is then calculated from these fifteen coordination numbers and this quantity is output to a file. 55 : 56 : \plumedfile 57 : mat2: CONTACT_MATRIX ATOMSA=1-5 ATOMSB=6-15 SWITCH={RATIONAL R_0=1.0} 58 : rsums: COLUMNSUMS MATRIX=mat2 MEAN 59 : PRINT ARG=rsums.* FILE=colvar 60 : \endplumedfile 61 : 62 : */ 63 : //+ENDPLUMEDOC 64 : 65 : namespace PLMD { 66 : namespace adjmat { 67 : 68 : class MatrixColumnSums : public ActionWithInputMatrix { 69 : public: 70 : static void registerKeywords( Keywords& keys ); 71 : explicit MatrixColumnSums(const ActionOptions&); 72 : double compute( const unsigned& tinded, multicolvar::AtomValuePack& myatoms ) const override; 73 : }; 74 : 75 13795 : PLUMED_REGISTER_ACTION(MatrixColumnSums,"COLUMNSUMS") 76 : 77 9 : void MatrixColumnSums::registerKeywords( Keywords& keys ) { 78 9 : ActionWithInputMatrix::registerKeywords( keys ); 79 9 : keys.use("ALT_MIN"); 80 9 : keys.use("LOWEST"); 81 9 : keys.use("HIGHEST"); 82 9 : keys.use("MEAN"); 83 9 : keys.use("MIN"); 84 9 : keys.use("MAX"); 85 9 : keys.use("LESS_THAN"); 86 9 : keys.use("MORE_THAN"); 87 9 : keys.use("BETWEEN"); 88 9 : keys.use("HISTOGRAM"); 89 9 : keys.use("MOMENTS"); 90 9 : } 91 : 92 5 : MatrixColumnSums::MatrixColumnSums(const ActionOptions& ao): 93 : Action(ao), 94 5 : ActionWithInputMatrix(ao) { 95 5 : if( (mymatrix->getMatrixAction())->mybasemulticolvars.size()>0 ) { 96 0 : error("matrix row sums should only be calculated when inputs are atoms"); 97 : } 98 : // Setup the tasks 99 5 : unsigned ncols = mymatrix->getNumberOfColumns(); 100 5 : ablocks.resize(1); 101 5 : ablocks[0].resize( ncols ); 102 155 : for(unsigned i=0; i<ncols; ++i) { 103 150 : addTaskToList( i ); 104 : } 105 : // Set the positions - this is only used when getting positions for central atoms 106 5 : if( mymatrix->undirectedGraph() ) { 107 144 : for(unsigned i=0; i<ncols; ++i) { 108 140 : ablocks[0][i]=i; 109 : } 110 : } else { 111 11 : for(unsigned i=0; i<ncols; ++i) { 112 10 : ablocks[0][i]=mymatrix->getNumberOfRows() + i; 113 : } 114 : } 115 : std::vector<AtomNumber> fake_atoms; 116 5 : setupMultiColvarBase( fake_atoms ); 117 5 : } 118 : 119 238 : double MatrixColumnSums::compute( const unsigned& tinded, multicolvar::AtomValuePack& myatoms ) const { 120 : double sum=0.0; 121 238 : std::vector<double> tvals( mymatrix->getNumberOfComponents() ); 122 238 : unsigned nrows = mymatrix->getNumberOfRows(); 123 9200 : for(unsigned i=0; i<nrows; ++i) { 124 8962 : if( mymatrix->undirectedGraph() && tinded==i ) { 125 188 : continue; 126 : } 127 8774 : sum+=retrieveConnectionValue( i, tinded, tvals ); 128 : } 129 : 130 238 : if( !doNotCalculateDerivatives() ) { 131 110 : MultiValue myvals( mymatrix->getNumberOfComponents(), myatoms.getNumberOfDerivatives() ); 132 : MultiValue& myvout=myatoms.getUnderlyingMultiValue(); 133 880 : for(unsigned i=0; i<nrows; ++i) { 134 770 : if( mymatrix->isSymmetric() && tinded==i ) { 135 60 : continue ; 136 : } 137 710 : addConnectionDerivatives( i, tinded, myvals, myvout ); 138 : } 139 110 : } 140 238 : return sum; 141 : } 142 : 143 : } 144 : }