Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2012-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 "FunctionShortcut.h" 23 : #include "FunctionOfScalar.h" 24 : #include "FunctionOfVector.h" 25 : #include "core/ActionRegister.h" 26 : #include "FunctionTemplateBase.h" 27 : 28 : namespace PLMD { 29 : namespace function { 30 : 31 : //+PLUMEDOC FUNCTION SORT 32 : /* 33 : This function can be used to sort colvars according to their magnitudes. 34 : 35 : This action sorts the input arguments according to their magnitudes. It will output the same number of values as it has arguments. 36 : The lowest argument input will be output as a value labelled _label_.1, the second lowest input argument will be output as a value labelled _label_.2 and so on. 37 : Thus, for example, the following input can be used to print the distance of the closest and of the farthest atoms to atom 1, chosen among atoms from 2 to 5 38 : 39 : ```plumed 40 : d12: DISTANCE ATOMS=1,2 41 : d13: DISTANCE ATOMS=1,3 42 : d14: DISTANCE ATOMS=1,4 43 : d15: DISTANCE ATOMS=1,5 44 : sort: SORT ARG=d12,d13,d14,d15 45 : PRINT ARG=sort.1,sort.4 46 : ``` 47 : 48 : Notice that you can also achieve the same result using the following input: 49 : 50 : ```plumed 51 : d: DISTANCE ATOMS1=1,2 ATOMS2=1,3 ATOMS3=1,4 ATOMS4=1,5 52 : sort: SORT ARG=d 53 : PRINT ARG=sort.1,sort.4 54 : ``` 55 : 56 : In this second case the four distances are passed to the SORT action as a vector. The SORT action then outputs 4 components - the same number of components as there 57 : are elements in the input vector - that contain the elements of the input vector in order of increasing magnitude. 58 : 59 : These examples are representative the only two ways you can use this action. In input it can accept either a list of scalars or a single vector. 60 : It does not accept matrices or a list of vectors in input. 61 : 62 : */ 63 : //+ENDPLUMEDOC 64 : 65 : //+PLUMEDOC FUNCTION SORT_SCALAR 66 : /* 67 : Sort the input scalars in a vector according to their magnitudes 68 : 69 : \par Examples 70 : 71 : */ 72 : //+ENDPLUMEDOC 73 : 74 : //+PLUMEDOC FUNCTION SORT_VECTOR 75 : /* 76 : Sort the elements in a vector according to their magnitudes 77 : 78 : \par Examples 79 : 80 : */ 81 : //+ENDPLUMEDOC 82 : 83 99 : class Sort : public FunctionTemplateBase { 84 : private: 85 : bool scalar_out; 86 : unsigned nargs; 87 : public: 88 : void registerKeywords(Keywords& keys) override ; 89 : void read( ActionWithArguments* action ) override; 90 0 : bool zeroRank() const override { 91 0 : return true; 92 : } 93 0 : bool doWithTasks() const override { 94 38 : return !scalar_out; 95 : } 96 : std::vector<std::string> getComponentsPerLabel() const override ; 97 : void setPeriodicityForOutputs( ActionWithValue* action ) override; 98 : void calc( const ActionWithArguments* action, const std::vector<double>& args, std::vector<double>& vals, Matrix<double>& derivatives ) const override; 99 : }; 100 : 101 : typedef FunctionShortcut<Sort> SortShortcut; 102 : PLUMED_REGISTER_ACTION(SortShortcut,"SORT") 103 : typedef FunctionOfScalar<Sort> ScalarSort; 104 : PLUMED_REGISTER_ACTION(ScalarSort,"SORT_SCALAR") 105 : typedef FunctionOfVector<Sort> VectorSort; 106 : PLUMED_REGISTER_ACTION(VectorSort,"SORT_VECTOR") 107 : 108 65 : void Sort::registerKeywords(Keywords& keys) { 109 130 : keys.setValueDescription("vector","sorted"); 110 65 : keys.setComponentsIntroduction("The names of the components in this action will be customized in accordance with the contents of the input file. " 111 : "The largest value is called label.1th, the second largest label.2th, the third label.3th and so on"); 112 65 : } 113 : 114 : 115 17 : void Sort::read( ActionWithArguments* action ) { 116 17 : scalar_out = action->getNumberOfArguments()==1; 117 17 : nargs = action->getNumberOfArguments(); 118 17 : if( scalar_out ) { 119 11 : nargs = action->getPntrToArgument(0)->getNumberOfValues(); 120 : } 121 : 122 48 : for(unsigned i=0; i<action->getNumberOfArguments(); ++i) { 123 32 : if((action->getPntrToArgument(i))->isPeriodic()) { 124 2 : action->error("Cannot sort periodic values (check argument "+ (action->getPntrToArgument(i))->getName() +")"); 125 : } 126 : } 127 16 : } 128 : 129 16 : std::vector<std::string> Sort::getComponentsPerLabel() const { 130 : std::vector<std::string> comp; 131 : std::string num; 132 61 : for(unsigned i=0; i<nargs; ++i) { 133 45 : Tools::convert(i+1,num); 134 45 : comp.push_back( num ); 135 : } 136 16 : return comp; 137 0 : } 138 : 139 16 : void Sort::setPeriodicityForOutputs( ActionWithValue* action ) { 140 61 : for(unsigned i=0; i<nargs; ++i) { 141 : std::string num; 142 45 : Tools::convert(i+1,num); 143 45 : action->componentIsNotPeriodic( num ); 144 : } 145 16 : } 146 : 147 45 : void Sort::calc( const ActionWithArguments* action, const std::vector<double>& args, std::vector<double>& vals, Matrix<double>& derivatives ) const { 148 45 : std::vector<std::pair<double,int> > data(args.size()); 149 326 : for(unsigned i=0; i<args.size(); ++i) { 150 281 : data[i].first=args[i]; 151 : // In this manner I remember from which argument the component depends: 152 281 : data[i].second=i; 153 : } 154 : // STL sort sorts based on first element (value) then second (index) 155 45 : std::sort(data.begin(),data.end()); 156 : derivatives = 0; 157 326 : for(int i=0; i<vals.size(); ++i) { 158 281 : vals[i] = data[i].first; 159 281 : derivatives(i, data[i].second ) = 1; 160 : } 161 45 : } 162 : 163 : } 164 : } 165 : 166 :