Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2014-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 "MatrixOperationBase.h" 23 : #include "core/ActionRegister.h" 24 : 25 : //+PLUMEDOC ANALYSIS DIAGONALIZE 26 : /* 27 : Calculate the eigenvalues and eigenvectors of a square matrix 28 : 29 : \par Examples 30 : 31 : */ 32 : //+ENDPLUMEDOC 33 : 34 : namespace PLMD { 35 : namespace matrixtools { 36 : 37 : class DiagonalizeMatrix : public MatrixOperationBase { 38 : private: 39 : std::vector<unsigned> desired_vectors; 40 : Matrix<double> mymatrix; 41 : std::vector<double> eigvals; 42 : Matrix<double> eigvecs; 43 : public: 44 : static void registerKeywords( Keywords& keys ); 45 : /// Constructor 46 : explicit DiagonalizeMatrix(const ActionOptions&); 47 : /// This is required to set the number of derivatives for the eigenvalues 48 276 : unsigned getNumberOfDerivatives() override { 49 276 : return getPntrToArgument(0)->getNumberOfValues(); 50 : } 51 : /// 52 : void prepare() override ; 53 : /// 54 : void calculate() override ; 55 : /// 56 : double getForceOnMatrixElement( const unsigned& jrow, const unsigned& krow ) const override; 57 : }; 58 : 59 : PLUMED_REGISTER_ACTION(DiagonalizeMatrix,"DIAGONALIZE") 60 : 61 41 : void DiagonalizeMatrix::registerKeywords( Keywords& keys ) { 62 41 : MatrixOperationBase::registerKeywords( keys ); 63 82 : keys.add("compulsory","VECTORS","all","the eigenvalues and vectors that you would like to calculate. 1=largest, 2=second largest and so on"); 64 82 : keys.addOutputComponent("vals","default","the eigevalues of the input matrix"); 65 82 : keys.addOutputComponent("vecs","default","the eigenvectors of the input matrix"); 66 41 : } 67 : 68 22 : DiagonalizeMatrix::DiagonalizeMatrix(const ActionOptions& ao): 69 : Action(ao), 70 22 : MatrixOperationBase(ao) { 71 22 : if( getPntrToArgument(0)->getShape()[0]!=getPntrToArgument(0)->getShape()[1] ) { 72 0 : error("input matrix should be square"); 73 : } 74 : 75 : std::vector<std::string> eigv; 76 44 : parseVector("VECTORS",eigv); 77 22 : if( eigv.size()>1 ) { 78 10 : Tools::interpretRanges(eigv); 79 10 : desired_vectors.resize( eigv.size() ); 80 30 : for(unsigned i=0; i<eigv.size(); ++i) { 81 20 : Tools::convert( eigv[i], desired_vectors[i] ); 82 : } 83 : } else { 84 12 : if( eigv.size()==0 ) { 85 0 : error("missing input to VECTORS keyword"); 86 : } 87 : unsigned ivec; 88 12 : if( eigv[0]=="all" ) { 89 7 : desired_vectors.resize( getPntrToArgument(0)->getShape()[0] ); 90 21 : for(unsigned i=0; i<desired_vectors.size(); ++i) { 91 14 : desired_vectors[i] = i + 1; 92 : } 93 : } else { 94 5 : Tools::convert( eigv[0], ivec ); 95 5 : desired_vectors.resize(1); 96 5 : desired_vectors[0]=ivec; 97 : } 98 : } 99 : 100 : std::string num; 101 22 : std::vector<unsigned> eval_shape(0); 102 22 : std::vector<unsigned> evec_shape(1); 103 22 : evec_shape[0] = getPntrToArgument(0)->getShape()[0]; 104 61 : for(unsigned i=0; i<desired_vectors.size(); ++i) { 105 39 : Tools::convert( desired_vectors[i], num ); 106 39 : addComponent( "vals-" + num, eval_shape ); 107 39 : componentIsNotPeriodic( "vals-" + num ); 108 39 : addComponent( "vecs-" + num, evec_shape ); 109 39 : componentIsNotPeriodic( "vecs-" + num ); 110 : // Make sure eigenvalues are always stored 111 39 : getPntrToComponent( 2*i+1 )->buildDataStore(); 112 : } 113 : 114 22 : std::vector<unsigned> eigvecs_shape(2); 115 22 : eigvecs_shape[0]=eigvecs_shape[1]=getPntrToArgument(0)->getShape()[0]; 116 22 : mymatrix.resize( eigvecs_shape[0], eigvecs_shape[1] ); 117 22 : eigvals.resize( eigvecs_shape[0] ); 118 22 : eigvecs.resize( eigvecs_shape[0], eigvecs_shape[1] ); 119 22 : } 120 : 121 124 : void DiagonalizeMatrix::prepare() { 122 124 : std::vector<unsigned> shape(1); 123 124 : shape[0]=getPntrToArgument(0)->getShape()[0]; 124 303 : for(unsigned i=0; i<desired_vectors.size(); ++i) { 125 179 : if( getPntrToComponent( 2*i+1 )->getShape()[0]!=shape[0] ) { 126 9 : getPntrToComponent( 2*i+1 )->setShape( shape ); 127 : } 128 : } 129 : 130 124 : } 131 : 132 122 : void DiagonalizeMatrix::calculate() { 133 122 : if( getPntrToArgument(0)->getShape()[0]==0 ) { 134 : return ; 135 : } 136 : // Resize stuff that might need resizing 137 : unsigned nvals=getPntrToArgument(0)->getShape()[0]; 138 122 : if( eigvals.size()!=nvals ) { 139 : mymatrix.resize( nvals, nvals ); 140 5 : eigvals.resize( nvals ); 141 : eigvecs.resize( nvals, nvals ); 142 : } 143 : 144 : // Retrieve the matrix from input 145 122 : retrieveFullMatrix( mymatrix ); 146 : // Now diagonalize the matrix 147 122 : diagMat( mymatrix, eigvals, eigvecs ); 148 : // And set the eigenvalues and eigenvectors 149 297 : for(unsigned i=0; i<desired_vectors.size(); ++i) { 150 175 : getPntrToComponent(2*i)->set( eigvals[ mymatrix.ncols()-desired_vectors[i]] ); 151 175 : Value* evec_out = getPntrToComponent(2*i+1); 152 175 : unsigned vreq = mymatrix.ncols()-desired_vectors[i]; 153 4526 : for(unsigned j=0; j<mymatrix.ncols(); ++j) { 154 4351 : evec_out->set( j, eigvecs( vreq, j ) ); 155 : } 156 : } 157 : } 158 : 159 12495 : double DiagonalizeMatrix::getForceOnMatrixElement( const unsigned& jrow, const unsigned& kcol ) const { 160 : double ff = 0; 161 31654 : for(unsigned i=0; i<desired_vectors.size(); ++i) { 162 : // Deal with forces on eigenvalues 163 19159 : if( getConstPntrToComponent(2*i)->forcesWereAdded() ) { 164 8330 : unsigned ncol = mymatrix.ncols()-desired_vectors[i]; 165 8330 : ff += getConstPntrToComponent(2*i)->getForce(0)*eigvecs(ncol,jrow)*eigvecs(ncol,kcol); 166 : } 167 : // And forces on eigenvectors 168 19159 : if( !getConstPntrToComponent(2*i+1)->forcesWereAdded() ) { 169 : continue; 170 : } 171 : 172 7497 : unsigned ncol = mymatrix.ncols()-desired_vectors[i]; 173 106624 : for(unsigned n=0; n<mymatrix.nrows(); ++n) { 174 : double tmp2 = 0; 175 1446088 : for(unsigned m=0; m<mymatrix.nrows(); ++m) { 176 1346961 : if( m==ncol ) { 177 99127 : continue; 178 : } 179 1247834 : tmp2 += eigvecs(m,n)*eigvecs(m,jrow)*eigvecs(ncol,kcol) / (eigvals[ncol]-eigvals[m]); 180 : } 181 99127 : ff += getConstPntrToComponent(2*i+1)->getForce(n) * tmp2; 182 : } 183 : } 184 12495 : return ff; 185 : } 186 : 187 : } 188 : }