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 "core/ActionShortcut.h" 23 : #include "core/ActionRegister.h" 24 : #include "core/ActionWithValue.h" 25 : #include "core/PlumedMain.h" 26 : #include "core/ActionSet.h" 27 : 28 : //+PLUMEDOC MATRIXF SPRINT 29 : /* 30 : Calculate SPRINT topological variables from an adjacency matrix. 31 : 32 : The SPRINT topological variables are calculated from the largest eigenvalue, $\lambda$ of 33 : an $n\times n$ adjacency matrix and its corresponding eigenvector, $V$, using: 34 : 35 : $$ 36 : s_i = \sqrt{n} \lambda v_i 37 : $$ 38 : 39 : The example input below calculates the 7 SPRINT coordinates for a 7 atom cluster of Lennard-Jones 40 : atoms and prints their values to a file. 41 : 42 : ```plumed 43 : ss: SPRINT GROUP=1-7 SWITCH={RATIONAL R_0=0.1} 44 : PRINT ARG=ss.* FILE=colvar 45 : ``` 46 : 47 : This example input calculates the 14 SPRINT coordinates for a molecule composed of 7 hydrogen and 48 : 7 carbon atoms. 49 : 50 : ```plumed 51 : ss: SPRINT ... 52 : GROUP1=1-7 GROUP2=8-14 53 : SWITCH11={RATIONAL R_0=2.6 NN=6 MM=12} 54 : SWITCH12={RATIONAL R_0=2.2 NN=6 MM=12} 55 : SWITCH22={RATIONAL R_0=2.2 NN=6 MM=12} 56 : ... 57 : 58 : PRINT ARG=ss.* FILE=colvar 59 : ``` 60 : 61 : If you explore the inputs above you can see that when PLUMED reads them it creates a more complicated input file 62 : for calculating the SPRINT CVs. You can get a sense of how these CVs are calculated by looking at the 63 : expanded versions of the shortcuts in the inputs above. The insight into these methods that you can obtain by looking 64 : at these expanded input should hopefully give you ideas for developing new versions of these methods that use the same 65 : body of theory. For example, if you look at the inputs above you can see that one or more [CONTACT_MATRIX](CONTACT_MATRIX.md) actions are 66 : used to calculate sprint. These CONTACT_MATRIX determine whether atoms are adjacent or not. However, you can 67 : use different quantities to measure whether or not two given atoms/molecules are 68 : adjacent or not and compute a different type of adjacency matrix. For example you can say that two molecules are 69 : adjacent if they are within a certain distance of each other and if they have similar orientations or you can argue that 70 : two molecules are adjacent if there is a hydrogen bond between them. 71 : */ 72 : //+ENDPLUMEDOC 73 : 74 : namespace PLMD { 75 : namespace sprint { 76 : 77 : class Sprint : public ActionShortcut { 78 : public: 79 : static void registerKeywords(Keywords& keys); 80 : explicit Sprint(const ActionOptions&); 81 : }; 82 : 83 : PLUMED_REGISTER_ACTION(Sprint,"SPRINT") 84 : 85 3 : void Sprint::registerKeywords(Keywords& keys) { 86 3 : ActionShortcut::registerKeywords( keys ); 87 3 : keys.add("optional","MATRIX","the matrix that you would like to perform SPRINT on"); 88 3 : keys.add("numbered","GROUP","specifies the list of atoms that should be assumed indistinguishable"); 89 3 : keys.add("numbered","SWITCH","specify the switching function to use between two sets of indistinguishable atoms"); 90 3 : keys.needsAction("CONTACT_MATRIX"); 91 3 : keys.needsAction("DIAGONALIZE"); 92 3 : keys.needsAction("CUSTOM"); 93 3 : keys.needsAction("SELECT_COMPONENTS"); 94 3 : keys.needsAction("SORT"); 95 3 : keys.needsAction("COMBINE"); 96 6 : keys.addOutputComponent("coord","default","scalar","the sprint coordinates"); 97 3 : keys.addDOI("10.1103/PhysRevLett.107.085504"); 98 3 : } 99 : 100 1 : Sprint::Sprint(const ActionOptions& ao): 101 : Action(ao), 102 1 : ActionShortcut(ao) { 103 : std::string matinp; 104 2 : parse("MATRIX",matinp); 105 1 : if( matinp.length()==0 ) { 106 2 : readInputLine( getShortcutLabel() + "_jmat: CONTACT_MATRIX " + convertInputLineToString() ); 107 2 : matinp = getShortcutLabel() + "_jmat"; 108 : } 109 : std::vector<unsigned> nin_group; 110 1 : unsigned ntot_atoms=0; 111 1 : for(unsigned i=1;; ++i) { 112 : std::string inum; 113 3 : Tools::convert( i, inum ); 114 6 : ActionWithValue* av = plumed.getActionSet().selectWithLabel<ActionWithValue*>( matinp + inum + inum ); 115 3 : if( !av ) { 116 : break ; 117 : } 118 2 : unsigned natoms = (av->copyOutput(0))->getShape()[0]; 119 2 : nin_group.push_back( natoms ); 120 2 : ntot_atoms += natoms; 121 2 : } 122 1 : if( nin_group.size()==0 ) { 123 0 : ActionWithValue* av = plumed.getActionSet().selectWithLabel<ActionWithValue*>( matinp ); 124 0 : unsigned natoms = (av->copyOutput(0))->getShape()[0]; 125 0 : nin_group.push_back( natoms ); 126 0 : ntot_atoms = natoms; 127 : } 128 : 129 : // Diagonalization 130 2 : readInputLine( getShortcutLabel() + "_diag: DIAGONALIZE ARG=" + matinp + " VECTORS=1"); 131 : // Compute sprint coordinates as product of eigenvalue and eigenvector times square root of number of atoms in all groups 132 : std::string str_natoms; 133 1 : Tools::convert( ntot_atoms, str_natoms ); 134 3 : readInputLine( getShortcutLabel() + "_sp: CUSTOM ARG=" + getShortcutLabel() + "_diag.vals-1," + getShortcutLabel() + 135 2 : "_diag.vecs-1 FUNC=sqrt(" + str_natoms + ")*x*y PERIODIC=NO"); 136 : // Sort sprint coordinates for each group of atoms 137 1 : unsigned k=0, kk=0; 138 3 : for(unsigned j=0; j<nin_group.size(); ++j) { 139 : std::string jnum, knum; 140 2 : Tools::convert( j+1, jnum ); 141 2 : Tools::convert(k+1, knum); 142 : k++; 143 4 : std::string sort_act = getShortcutLabel() + "_selection" + jnum + ": SELECT_COMPONENTS ARG=" + getShortcutLabel() + "_sp COMPONENTS=" + knum; 144 14 : for(unsigned n=1; n<nin_group[j]; ++n) { 145 12 : Tools::convert( k+1, knum ); 146 24 : sort_act += ","+ knum; 147 : k++; 148 : } 149 2 : readInputLine( sort_act ); 150 4 : readInputLine( getShortcutLabel() + jnum + ": SORT ARG=" + getShortcutLabel() + "_selection" + jnum ); 151 16 : for(unsigned n=0; n<nin_group[j]; ++n) { 152 : std::string knum, nnum; 153 14 : Tools::convert( kk, knum ); 154 14 : Tools::convert( n+1, nnum ); 155 14 : kk++; 156 28 : readInputLine( getShortcutLabel() + "_coord-" + knum + ": COMBINE ARG=" + getShortcutLabel() + jnum + "." + nnum + " PERIODIC=NO" ); 157 : } 158 : } 159 1 : } 160 : 161 : } 162 : }