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 : In the example input below we measure adjacency between atoms using a [BRIDGE_MATRIX](BRIDGE_MATRIX.md) and then compute the SPRINT CVs 73 : by diagonalizing this matrix. 74 : 75 : ```plumed 76 : b: BRIDGE_MATRIX GROUP=1-7 BRIDGING_ATOMS=8-100 SWITCH={RATIONAL R_0=0.2} 77 : s: SPRINT MATRIX=b 78 : PRINT ARG=s.* FILE=colvar 79 : ``` 80 : 81 : */ 82 : //+ENDPLUMEDOC 83 : 84 : namespace PLMD { 85 : namespace sprint { 86 : 87 : class Sprint : public ActionShortcut { 88 : public: 89 : static void registerKeywords(Keywords& keys); 90 : explicit Sprint(const ActionOptions&); 91 : }; 92 : 93 : PLUMED_REGISTER_ACTION(Sprint,"SPRINT") 94 : 95 15 : void Sprint::registerKeywords(Keywords& keys) { 96 15 : ActionShortcut::registerKeywords( keys ); 97 15 : keys.add("optional","MATRIX","the matrix that you would like to perform SPRINT on"); 98 15 : keys.add("numbered","GROUP","specifies the list of atoms that should be assumed indistinguishable"); 99 15 : keys.add("numbered","SWITCH","specify the switching function to use between two sets of indistinguishable atoms"); 100 15 : keys.needsAction("CONTACT_MATRIX"); 101 15 : keys.needsAction("DIAGONALIZE"); 102 15 : keys.needsAction("CUSTOM"); 103 15 : keys.needsAction("SELECT_COMPONENTS"); 104 15 : keys.needsAction("SORT"); 105 15 : keys.needsAction("COMBINE"); 106 30 : keys.addOutputComponent("coord","default","scalar","the sprint coordinates"); 107 15 : keys.addDOI("10.1103/PhysRevLett.107.085504"); 108 15 : } 109 : 110 6 : Sprint::Sprint(const ActionOptions& ao): 111 : Action(ao), 112 6 : ActionShortcut(ao) { 113 : std::string matinp; 114 12 : parse("MATRIX",matinp); 115 6 : if( matinp.length()==0 ) { 116 4 : readInputLine( getShortcutLabel() + "_jmat: CONTACT_MATRIX " + convertInputLineToString() ); 117 4 : matinp = getShortcutLabel() + "_jmat"; 118 : } 119 6 : std::vector<unsigned> nin_group; 120 6 : unsigned ntot_atoms=0; 121 6 : for(unsigned i=1;; ++i) { 122 : std::string inum; 123 10 : Tools::convert( i, inum ); 124 10 : ActionWithValue* av = plumed.getActionSet().selectWithLabel<ActionWithValue*>( matinp + inum + inum ); 125 10 : if( !av ) { 126 : break ; 127 : } 128 4 : unsigned natoms = (av->copyOutput(0))->getShape()[0]; 129 4 : nin_group.push_back( natoms ); 130 4 : ntot_atoms += natoms; 131 4 : } 132 6 : if( nin_group.size()==0 ) { 133 4 : ActionWithValue* av = plumed.getActionSet().selectWithLabel<ActionWithValue*>( matinp ); 134 4 : unsigned natoms = (av->copyOutput(0))->getShape()[0]; 135 4 : nin_group.push_back( natoms ); 136 4 : ntot_atoms = natoms; 137 : } 138 : 139 : // Diagonalization 140 18 : readInputLine( getShortcutLabel() + "_diag: DIAGONALIZE ARG=" + matinp + " VECTORS=1"); 141 : // Compute sprint coordinates as product of eigenvalue and eigenvector times square root of number of atoms in all groups 142 : std::string str_natoms; 143 6 : Tools::convert( ntot_atoms, str_natoms ); 144 18 : readInputLine( getShortcutLabel() + "_sp: CUSTOM ARG=" + getShortcutLabel() + "_diag.vecs-1," + getShortcutLabel() + 145 6 : "_diag.vals-1 FUNC=sqrt(" + str_natoms + ")*x*y PERIODIC=NO"); 146 : // Sort sprint coordinates for each group of atoms 147 6 : unsigned k=0, kk=0; 148 14 : for(unsigned j=0; j<nin_group.size(); ++j) { 149 : std::string jnum; 150 : std::string knum; 151 : std::string nnum; 152 8 : Tools::convert( j+1, jnum ); 153 8 : Tools::convert(k+1, knum); 154 : k++; 155 24 : std::string sort_act = getShortcutLabel() + "_selection" + jnum + ": SELECT_COMPONENTS ARG=" + getShortcutLabel() + "_sp COMPONENTS=" + knum; 156 84 : for(unsigned n=1; n<nin_group[j]; ++n) { 157 76 : Tools::convert( k+1, knum ); 158 76 : sort_act += ","+ knum; 159 : k++; 160 : } 161 8 : readInputLine( sort_act ); 162 24 : readInputLine( getShortcutLabel() + jnum + ": SORT ARG=" + getShortcutLabel() + "_selection" + jnum ); 163 92 : for(unsigned n=0; n<nin_group[j]; ++n) { 164 84 : Tools::convert( kk, knum ); 165 84 : Tools::convert( n+1, nnum ); 166 84 : kk++; 167 420 : readInputLine( getShortcutLabel() + "_coord-" + knum + ": COMBINE ARG=" + getShortcutLabel() + jnum + "." + nnum + " PERIODIC=NO" ); 168 : } 169 : } 170 88 : } 171 : 172 : } 173 : }