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 10429 : PLUMED_REGISTER_ACTION(MatrixColumnSums,"COLUMNSUMS") 76 : 77 6 : void MatrixColumnSums::registerKeywords( Keywords& keys ) { 78 6 : ActionWithInputMatrix::registerKeywords( keys ); 79 18 : keys.use("ALT_MIN"); keys.use("LOWEST"); keys.use("HIGHEST"); 80 24 : keys.use("MEAN"); keys.use("MIN"); keys.use("MAX"); keys.use("LESS_THAN"); 81 24 : keys.use("MORE_THAN"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS"); 82 6 : } 83 : 84 5 : MatrixColumnSums::MatrixColumnSums(const ActionOptions& ao): 85 : Action(ao), 86 5 : ActionWithInputMatrix(ao) 87 : { 88 5 : if( (mymatrix->getMatrixAction())->mybasemulticolvars.size()>0 ) error("matrix row sums should only be calculated when inputs are atoms"); 89 : // Setup the tasks 90 5 : unsigned ncols = mymatrix->getNumberOfColumns(); 91 5 : ablocks.resize(1); ablocks[0].resize( ncols ); 92 155 : for(unsigned i=0; i<ncols; ++i) addTaskToList( i ); 93 : // Set the positions - this is only used when getting positions for central atoms 94 5 : if( mymatrix->undirectedGraph() ) { 95 144 : for(unsigned i=0; i<ncols; ++i) ablocks[0][i]=i; 96 : } else { 97 11 : for(unsigned i=0; i<ncols; ++i) ablocks[0][i]=mymatrix->getNumberOfRows() + i; 98 : } 99 5 : std::vector<AtomNumber> fake_atoms; setupMultiColvarBase( fake_atoms ); 100 5 : } 101 : 102 238 : double MatrixColumnSums::compute( const unsigned& tinded, multicolvar::AtomValuePack& myatoms ) const { 103 238 : double sum=0.0; std::vector<double> tvals( mymatrix->getNumberOfComponents() ); 104 238 : unsigned nrows = mymatrix->getNumberOfRows(); 105 9200 : for(unsigned i=0; i<nrows; ++i) { 106 8962 : if( mymatrix->undirectedGraph() && tinded==i ) continue; 107 8774 : sum+=retrieveConnectionValue( i, tinded, tvals ); 108 : } 109 : 110 238 : if( !doNotCalculateDerivatives() ) { 111 110 : MultiValue myvals( mymatrix->getNumberOfComponents(), myatoms.getNumberOfDerivatives() ); 112 : MultiValue& myvout=myatoms.getUnderlyingMultiValue(); 113 880 : for(unsigned i=0; i<nrows; ++i) { 114 770 : if( mymatrix->isSymmetric() && tinded==i ) continue ; 115 710 : addConnectionDerivatives( i, tinded, myvals, myvout ); 116 : } 117 110 : } 118 238 : return sum; 119 : } 120 : 121 : } 122 : }