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 "core/ActionShortcut.h" 23 : #include "core/ActionRegister.h" 24 : #include "core/ActionWithArguments.h" 25 : #include "core/PlumedMain.h" 26 : #include "core/ActionSet.h" 27 : 28 : //+PLUMEDOC PRINTANALYSIS SELECT_COMPONENTS 29 : /* 30 : Create a new value to hold a subset of the components that are in a vector or matrix 31 : 32 : Output a scalar or vector that contains a subset of the elements in the input vector or matrix. 33 : In the example below the value `s` is a scalar that contains the distance between atoms 3 and 4. 34 : 35 : ```plumed 36 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8 37 : s: SELECT_COMPONENTS ARG=d COMPONENTS=2 38 : ``` 39 : 40 : In this example the output z is a 2 dimensional vector containing the distances between atoms 3 and 4 41 : and 7 and 8. 42 : 43 : ```plumed 44 : d: DISTANCE ATOMS1=1,2 ATOMS2=3,4 ATOMS3=5,6 ATOMS4=7,8 45 : s: SELECT_COMPONENTS ARG=d COMPONENTS=2,4 46 : ``` 47 : 48 : Lastly, in this example we calculate a matrix of distances. The scalar `s` that is output from the 49 : SELECT_COMPONENTS action contains the distance between atoms 1 and 3 and 3 and 4. 50 : 51 : ```plumed 52 : d: DISTANCE_MATRIX GROUP=1-5 53 : s: SELECT_COMPONENTS ARG=d COMPONENTS=1.3,3.4 54 : ``` 55 : 56 : */ 57 : //+ENDPLUMEDOC 58 : 59 : namespace PLMD { 60 : namespace valtools { 61 : 62 : class SelectComponents : public ActionShortcut { 63 : public: 64 : static void registerKeywords( Keywords& keys ); 65 : /// Constructor 66 : explicit SelectComponents(const ActionOptions&); 67 : }; 68 : 69 : PLUMED_REGISTER_ACTION(SelectComponents,"SELECT_COMPONENTS") 70 : 71 69 : void SelectComponents::registerKeywords( Keywords& keys ) { 72 69 : ActionShortcut::registerKeywords( keys ); 73 138 : keys.addInputKeyword("compulsory","ARG","vector/matrix","the value from which we are selecting components"); 74 69 : keys.add("compulsory","COMPONENTS","the components in the input value that you woul like to build a new vector from"); 75 69 : keys.needsAction("FLATTEN"); 76 69 : keys.needsAction("CONSTANT"); 77 69 : keys.needsAction("SELECT_WITH_MASK"); 78 138 : keys.setValueDescription("vector","a vector containing the selected components"); 79 69 : } 80 : 81 57 : SelectComponents::SelectComponents(const ActionOptions& ao): 82 : Action(ao), 83 57 : ActionShortcut(ao) { 84 : std::vector<std::string> argn; 85 114 : parseVector("ARG",argn); 86 : std::vector<Value*> theargs; 87 57 : ActionWithArguments::interpretArgumentList( argn, plumed.getActionSet(), this, theargs ); 88 57 : if( theargs.size()!=1 ) { 89 0 : error("should only be one argument input to this action"); 90 : } 91 : // Create an array that will eventually hold the mask 92 57 : std::vector<double> mask( theargs[0]->getNumberOfValues(), 1 ); 93 : std::vector<std::string> elements; 94 114 : parseVector("COMPONENTS",elements); 95 57 : if( theargs[0]->getRank()==1 ) { 96 189 : for(unsigned i=0; i<elements.size(); ++i) { 97 : unsigned sel; 98 139 : Tools::convert( elements[i], sel ); 99 139 : mask[sel-1]=0; 100 : } 101 7 : } else if( theargs[0]->getRank()==2 ) { 102 27 : for(unsigned i=0; i<elements.size(); ++i) { 103 20 : std::size_t dot = elements[i].find_first_of("."); 104 20 : if( dot==std::string::npos ) { 105 0 : error("found no dot in specification of required matrix element"); 106 : } 107 20 : std::string istr=elements[i].substr(0,dot), jstr=elements[i].substr(dot+1); 108 : unsigned ival, jval; 109 20 : Tools::convert( istr, ival ); 110 20 : Tools::convert( jstr, jval ); 111 20 : mask[(ival-1)*theargs[0]->getShape()[1] + jval - 1] = 0; 112 : } 113 14 : readInputLine( getShortcutLabel() + "_flat: FLATTEN ARG=" + theargs[0]->getName() ); 114 : } else { 115 0 : error("input to this argument should be a vector/matrix"); 116 : } 117 : // Now create the mask action 118 : std::string mask_str; 119 57 : Tools::convert( mask[0], mask_str ); 120 57 : unsigned check_mask=mask[0]; 121 1472 : for(unsigned i=1; i<mask.size(); ++i) { 122 : std::string num; 123 1415 : Tools::convert( mask[i], num ); 124 2830 : mask_str += "," + num; 125 1415 : check_mask +=mask[i]; 126 : } 127 57 : if( mask.size()-check_mask!=elements.size() ) { 128 0 : error("found repeated indexes in COMPONENTS"); 129 : } 130 114 : readInputLine( getShortcutLabel() + "_mask: CONSTANT VALUES=" + mask_str ); 131 : // And finally create the selector 132 57 : if( theargs[0]->getRank()==1 ) { 133 100 : readInputLine( getShortcutLabel() + ": SELECT_WITH_MASK ARG=" + theargs[0]->getName() + " MASK=" + getShortcutLabel() + "_mask"); 134 7 : } else if( theargs[0]->getRank()==2 ) { 135 14 : readInputLine( getShortcutLabel() + ": SELECT_WITH_MASK ARG=" + getShortcutLabel() + "_flat MASK=" + getShortcutLabel() + "_mask"); 136 : } 137 114 : } 138 : 139 : } 140 : }