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 "ActionWithValue.h" 23 : #include "tools/Exception.h" 24 : #include "tools/OpenMP.h" 25 : 26 : namespace PLMD { 27 : 28 5190 : void ActionWithValue::registerKeywords(Keywords& keys) { 29 5190 : keys.setComponentsIntroduction("By default the value of the calculated quantity can be referenced elsewhere in the " 30 : "input file by using the label of the action. Alternatively this Action can be used " 31 : "to calculate the following quantities by employing the keywords listed " 32 : "below. These quantities can be referenced elsewhere in the input by using this Action's " 33 : "label followed by a dot and the name of the quantity required from the list below."); 34 10380 : keys.addFlag("NUMERICAL_DERIVATIVES", false, "calculate the derivatives for these quantities numerically"); 35 10380 : keys.add("hidden","HAS_VALUES","this is used in json output to determine those actions that have values"); 36 5190 : } 37 : 38 0 : void ActionWithValue::noAnalyticalDerivatives(Keywords& keys) { 39 0 : keys.remove("NUMERICAL_DERIVATIVES"); 40 0 : keys.addFlag("NUMERICAL_DERIVATIVES",false,"analytical derivatives are not implemented for this keyword so numerical derivatives are always used"); 41 0 : } 42 : 43 1522 : void ActionWithValue::componentsAreNotOptional(Keywords& keys) { 44 1522 : keys.setComponentsIntroduction("By default this Action calculates the following quantities. These quantities can " 45 : "be referenced elsewhere in the input by using this Action's label followed by a " 46 : "dot and the name of the quantity required from the list below."); 47 1522 : } 48 : 49 286 : void ActionWithValue::useCustomisableComponents(Keywords& keys) { 50 286 : keys.setComponentsIntroduction("The names of the components in this action can be customized by the user in the " 51 : "actions input file. However, in addition to the components that can be customized the " 52 : "following quantities will always be output"); 53 286 : } 54 : 55 4322 : ActionWithValue::ActionWithValue(const ActionOptions&ao): 56 : Action(ao), 57 4322 : noderiv(true), 58 4322 : numericalDerivatives(false) { 59 8644 : if( keywords.exists("NUMERICAL_DERIVATIVES") ) { 60 7704 : parseFlag("NUMERICAL_DERIVATIVES",numericalDerivatives); 61 : } 62 4322 : if(numericalDerivatives) { 63 117 : log.printf(" using numerical derivatives\n"); 64 : } 65 4322 : } 66 : 67 4322 : ActionWithValue::~ActionWithValue() { 68 : // empty destructor to delete unique_ptr 69 4322 : } 70 : 71 1397729 : void ActionWithValue::clearInputForces() { 72 3502353 : for(unsigned i=0; i<values.size(); i++) { 73 : values[i]->clearInputForce(); 74 : } 75 1397729 : } 76 : 77 1400510 : void ActionWithValue::clearDerivatives() { 78 1400510 : unsigned nt = OpenMP::getNumThreads(); 79 1400510 : #pragma omp parallel num_threads(nt) 80 : { 81 : #pragma omp for 82 : for(unsigned i=0; i<values.size(); i++) { 83 : values[i]->clearDerivatives(); 84 : } 85 : } 86 1400510 : } 87 : 88 : // -- These are the routine for copying the value pointers to other classes -- // 89 : 90 11792118 : bool ActionWithValue::exists( const std::string& name ) const { 91 122293718 : for(unsigned i=0; i<values.size(); ++i) { 92 110527822 : if (values[i]->name==name) { 93 : return true; 94 : } 95 : } 96 : return false; 97 : } 98 : 99 26381 : Value* ActionWithValue::copyOutput( const std::string& name ) const { 100 11309072 : for(unsigned i=0; i<values.size(); ++i) { 101 11309072 : if (values[i]->name==name) { 102 26381 : return values[i].get(); 103 : } 104 : } 105 0 : plumed_merror("there is no pointer with name " + name); 106 : } 107 : 108 11111 : Value* ActionWithValue::copyOutput( const unsigned& n ) const { 109 11111 : plumed_massert(n<values.size(),"you have requested a pointer that is out of bounds"); 110 11111 : return values[n].get(); 111 : } 112 : 113 : // -- HERE WE HAVE THE STUFF FOR THE DEFAULT VALUE -- // 114 : 115 56 : void ActionWithValue::addValue() { 116 56 : plumed_massert(values.empty(),"You have already added the default value for this action"); 117 56 : values.emplace_back(Tools::make_unique<Value>(this,getLabel(), false ) ); 118 56 : } 119 : 120 2389 : void ActionWithValue::addValueWithDerivatives() { 121 2389 : plumed_massert(values.empty(),"You have already added the default value for this action"); 122 2389 : values.emplace_back(Tools::make_unique<Value>(this,getLabel(), true ) ); 123 2389 : } 124 : 125 1744 : void ActionWithValue::setNotPeriodic() { 126 1744 : plumed_massert(values.size()==1,"The number of components is not equal to one"); 127 1744 : plumed_massert(values[0]->name==getLabel(), "The value you are trying to set is not the default"); 128 1744 : values[0]->min=0; 129 1744 : values[0]->max=0; 130 1744 : values[0]->setupPeriodicity(); 131 1744 : } 132 : 133 701 : void ActionWithValue::setPeriodic( const std::string& min, const std::string& max ) { 134 701 : plumed_massert(values.size()==1,"The number of components is not equal to one"); 135 701 : plumed_massert(values[0]->name==getLabel(), "The value you are trying to set is not the default"); 136 701 : values[0]->setDomain( min, max ); 137 701 : } 138 : 139 16892095 : Value* ActionWithValue::getPntrToValue() { 140 : plumed_dbg_massert(values.size()==1,"The number of components is not equal to one"); 141 : plumed_dbg_massert(values[0]->name==getLabel(), "The value you are trying to retrieve is not the default"); 142 16892095 : return values[0].get(); 143 : } 144 : 145 : // -- HERE WE HAVE THE STUFF FOR NAMED VALUES / COMPONENTS -- // 146 : 147 23033 : void ActionWithValue::addComponent( const std::string& name ) { 148 23033 : if( !keywords.outputComponentExists(name,true) ) { 149 0 : plumed_merror("a description of component " + name + " has not been added to the manual. Components should be registered like keywords in " 150 : "registerKeywords as described in the developer docs."); 151 : } 152 : std::string thename; 153 46066 : thename=getLabel() + "." + name; 154 18686791 : for(unsigned i=0; i<values.size(); ++i) { 155 18663758 : plumed_massert(values[i]->name!=getLabel(),"Cannot mix single values with components"); 156 18663758 : plumed_massert(values[i]->name!=thename,"there is already a value with this name: "+thename); 157 18663758 : plumed_massert(values[i]->name!=thename&&name!="bias","Since PLUMED 2.3 the component 'bias' is automatically added to all biases by the general constructor!\n" 158 : "Remove the line addComponent(\"bias\") from your bias."); 159 : } 160 23033 : values.emplace_back(Tools::make_unique<Value>(this,thename, false ) ); 161 23033 : std::string msg=" added component to this action: "+thename+" \n"; 162 23033 : log.printf(msg.c_str()); 163 23033 : } 164 : 165 11007 : void ActionWithValue::addComponentWithDerivatives( const std::string& name ) { 166 11007 : if( !keywords.outputComponentExists(name,true) ) { 167 0 : plumed_merror("a description of component " + name + " has not been added to the manual. Components should be registered like keywords in " 168 : "registerKeywords as described in the developer doc."); 169 : } 170 : std::string thename; 171 22014 : thename=getLabel() + "." + name; 172 2442558 : for(unsigned i=0; i<values.size(); ++i) { 173 2431551 : plumed_massert(values[i]->name!=getLabel(),"Cannot mix single values with components"); 174 2431551 : plumed_massert(values[i]->name!=thename,"there is already a value with this name: "+thename); 175 2431551 : plumed_massert(values[i]->name!=thename&&name!="bias","Since PLUMED 2.3 the component 'bias' is automatically added to all biases by the general constructor!\n" 176 : "Remove the line addComponentWithDerivatives(\"bias\") from your bias."); 177 : } 178 11007 : values.emplace_back(Tools::make_unique<Value>(this,thename, true ) ); 179 11007 : std::string msg=" added component to this action: "+thename+" \n"; 180 11007 : log.printf(msg.c_str()); 181 11007 : } 182 : 183 11759062 : int ActionWithValue::getComponent( const std::string& name ) const { 184 11759062 : plumed_massert( !exists( getLabel() ), "You should not be calling this routine if you are using a value"); 185 : std::string thename; 186 23518124 : thename=getLabel() + "." + name; 187 65313395 : for(unsigned i=0; i<values.size(); ++i) { 188 65313395 : if (values[i]->name==thename) { 189 11759062 : return i; 190 : } 191 : } 192 0 : plumed_merror("there is no component with name " + name); 193 : } 194 : 195 0 : std::string ActionWithValue::getComponentsList( ) const { 196 : std::string complist; 197 0 : for(unsigned i=0; i<values.size(); ++i) { 198 0 : complist+=values[i]->name+" "; 199 : } 200 0 : return complist; 201 : } 202 : 203 1376 : std::vector<std::string> ActionWithValue::getComponentsVector( ) const { 204 : std::vector<std::string> complist; 205 220524 : for(unsigned i=0; i<values.size(); ++i) { 206 219148 : complist.push_back(values[i]->name); 207 : } 208 1376 : return complist; 209 0 : } 210 : 211 30847 : void ActionWithValue::componentIsNotPeriodic( const std::string& name ) { 212 30847 : int kk=getComponent(name); 213 30847 : values[kk]->min=0; 214 30847 : values[kk]->max=0; 215 30847 : values[kk]->setupPeriodicity(); 216 30847 : } 217 : 218 94 : void ActionWithValue::componentIsPeriodic( const std::string& name, const std::string& min, const std::string& max ) { 219 94 : int kk=getComponent(name); 220 94 : values[kk]->setDomain(min,max); 221 94 : } 222 : 223 1397729 : void ActionWithValue::setGradientsIfNeeded() { 224 2795458 : if(isOptionOn("GRADIENTS")) { 225 366 : for(unsigned i=0; i<values.size(); i++) { 226 183 : values[i]->setGradients(); 227 : } 228 : } 229 1397729 : } 230 : 231 3493530 : void ActionWithValue::turnOnDerivatives() { 232 : // Turn on the derivatives 233 3493530 : noderiv=false; 234 : // Resize the derivatives 235 4106214672 : for(unsigned i=0; i<values.size(); ++i) { 236 4102721142 : values[i]->resizeDerivatives( getNumberOfDerivatives() ); 237 : } 238 : // And turn on the derivatives in all actions on which we are dependent 239 7086225 : for(unsigned i=0; i<getDependencies().size(); ++i) { 240 3592695 : ActionWithValue* vv=dynamic_cast<ActionWithValue*>( getDependencies()[i] ); 241 3592695 : if(vv) { 242 3487964 : vv->turnOnDerivatives(); 243 : } 244 : } 245 3493530 : } 246 : 247 11728121 : Value* ActionWithValue::getPntrToComponent( const std::string& name ) { 248 11728121 : int kk=getComponent(name); 249 11728121 : return values[kk].get(); 250 : } 251 : 252 2163121 : Value* ActionWithValue::getPntrToComponent( int n ) { 253 : plumed_dbg_massert(n<values.size(),"you have requested a pointer that is out of bounds"); 254 2163121 : return values[n].get(); 255 : } 256 : 257 : }