Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2011-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 "core/ActionPilot.h" 23 : #include "core/ActionWithValue.h" 24 : #include "core/ActionWithArguments.h" 25 : #include "core/ActionRegister.h" 26 : #include "tools/File.h" 27 : 28 : namespace PLMD { 29 : namespace generic { 30 : 31 : //+PLUMEDOC PRINTANALYSIS DUMPDERIVATIVES 32 : /* 33 : Dump the derivatives with respect to the input parameters for scalar values (generally CVs, functions or biases). 34 : 35 : You can use this command to output the derivatives of a scalar with respect to whatever input parameters are used to 36 : calculate that scalar. For example, the following input instructs plumed to write a file called deriv that contains both the 37 : analytical and numerical derivatives of the distance between atoms 1 and 2. 38 : 39 : ```plumed 40 : distance: DISTANCE ATOMS=1,2 41 : distanceN: DISTANCE ATOMS=1,2 NUMERICAL_DERIVATIVES 42 : DUMPDERIVATIVES ARG=distance,distanceN STRIDE=1 FILE=deriv 43 : ``` 44 : 45 : This input outputs the derivative of the distance with respect to the atom positions and the cell vectors (virial-like form). 46 : It will thus output 15 deriatives for the two quantities output - the derivatives with respect to the x,y and z components of the input atoms 47 : and the 9 components of the virial. 48 : 49 : By contast the following input will only output 1 derivative; namely, the derivative of the switching function, `f`, with respect to the input distance, `d`. 50 : 51 : ```plumed 52 : d: DISTANCE ATOMS=1,2 53 : f: LESS_THAN ARG=d SWITCH={RATIONAL R_0=0.2} 54 : DUMPDERIVATIVES ARG=f STRIDE=1 FMT=%8.4f FILE=deriv 55 : ``` 56 : 57 : !!! warning "" 58 : 59 : You can only use this command to output the derivatives of rank 0 (scalar) values. 60 : You cannot use it to output derivatives of vector, matrix of function values. 61 : 62 : ## RESTART, UPDATE_FROM and UPDATE_UNTIL 63 : 64 : Notice that the RESTART, UPDATE_FROM and UPDATE_UNTIL keywords keywords 65 : can be used in this action in the same way as they are used for [PRINT](PRINT.md). 66 : Consequently, if you would like to append derivatives to an existing file called `deriv` instead of backing that 67 : file up at the start of the calculation and outputting the data from the calculation on a new file called `deriv` 68 : you would use an input like the one shown below: 69 : 70 : ```plumed 71 : distance: DISTANCE ATOMS=1,2 72 : DUMPDERIVATIVES ARG=distance STRIDE=1 FILE=deriv RESTART=YES 73 : ``` 74 : 75 : Similarly, if you want to only output the derivatives during the 400 ps time interval after the first 76 : 100 ps of the simulation you would use an input like the one shown below: 77 : 78 : ```plumed 79 : distance: DISTANCE ATOMS=1,2 80 : DUMPDERIVATIVES ARG=distance STRIDE=1 FILE=deriv UPDATE_FROM=100 UPDATE_UNTIL=500 81 : ``` 82 : 83 : */ 84 : //+ENDPLUMEDOC 85 : 86 : class DumpDerivatives : 87 : public ActionPilot, 88 : public ActionWithArguments { 89 : std::string file; 90 : std::string fmt; 91 : OFile of; 92 : public: 93 13782 : void calculate() override {} 94 : explicit DumpDerivatives(const ActionOptions&); 95 : static void registerKeywords(Keywords& keys); 96 13740 : void apply() override {} 97 : void update() override; 98 : ~DumpDerivatives(); 99 : }; 100 : 101 : PLUMED_REGISTER_ACTION(DumpDerivatives,"DUMPDERIVATIVES") 102 : 103 232 : void DumpDerivatives::registerKeywords(Keywords& keys) { 104 232 : Action::registerKeywords(keys); 105 232 : ActionPilot::registerKeywords(keys); 106 232 : ActionWithArguments::registerKeywords(keys); 107 464 : keys.addInputKeyword("compulsory","ARG","scalar","the labels of the values whose derivatives should be output"); 108 232 : keys.add("compulsory","STRIDE","1","the frequency with which the derivatives should be output"); 109 232 : keys.add("compulsory","FILE","the name of the file on which to output the derivatives"); 110 232 : keys.add("compulsory","FMT","%15.10f","the format with which the derivatives should be output"); 111 232 : keys.use("RESTART"); 112 232 : keys.use("UPDATE_FROM"); 113 232 : keys.use("UPDATE_UNTIL"); 114 232 : } 115 : 116 230 : DumpDerivatives::DumpDerivatives(const ActionOptions&ao): 117 : Action(ao), 118 : ActionPilot(ao), 119 : ActionWithArguments(ao), 120 230 : fmt("%15.10f") { 121 460 : parse("FILE",file); 122 230 : if( file.length()==0 ) { 123 0 : error("name of output file was not specified"); 124 : } 125 230 : parse("FMT",fmt); 126 230 : fmt=" "+fmt; 127 230 : of.link(*this); 128 230 : of.open(file); 129 230 : log.printf(" on file %s\n",file.c_str()); 130 230 : log.printf(" with format %s\n",fmt.c_str()); 131 : unsigned nargs=getNumberOfArguments(); 132 230 : if( nargs==0 ) { 133 0 : error("no arguments specified"); 134 : } 135 230 : (getPntrToArgument(0)->getPntrToAction())->turnOnDerivatives(); 136 230 : if( getPntrToArgument(0)->getRank()>0 ) { 137 0 : error("cannot dump derivatives of non-scalar objects"); 138 : } 139 230 : unsigned npar=getPntrToArgument(0)->getNumberOfDerivatives(); 140 230 : if( npar==0 ) { 141 0 : error("one or more arguments has no derivatives"); 142 : } 143 804 : for(unsigned i=1; i<nargs; i++) { 144 574 : (getPntrToArgument(i)->getPntrToAction())->turnOnDerivatives(); 145 574 : if( getPntrToArgument(i)->getRank()>0 ) { 146 0 : error("cannot dump derivatives of non-scalar objects"); 147 : } 148 574 : if( npar!=getPntrToArgument(i)->getNumberOfDerivatives() ) { 149 0 : error("the number of derivatives must be the same in all values being dumped"); 150 : } 151 : } 152 230 : checkRead(); 153 230 : } 154 : 155 : 156 9055 : void DumpDerivatives::update() { 157 9055 : unsigned npar=getPntrToArgument(0)->getNumberOfDerivatives(); 158 672414 : for(unsigned ipar=0; ipar<npar; ipar++) { 159 663359 : of.fmtField(" %f"); 160 663359 : of.printField("time",getTime()); 161 663359 : of.printField("parameter",(int)ipar); 162 3315611 : for(unsigned i=0; i<getNumberOfArguments(); i++) { 163 2652252 : of.fmtField(fmt); 164 2652252 : of.printField(getPntrToArgument(i)->getName(),getPntrToArgument(i)->getDerivative(ipar) ); 165 : } 166 663359 : of.printField(); 167 : } 168 9055 : } 169 : 170 460 : DumpDerivatives::~DumpDerivatives() { 171 460 : } 172 : 173 : } 174 : 175 : 176 : }