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 4328 : void ActionWithValue::registerKeywords(Keywords& keys) { 29 4328 : 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 8656 : keys.addFlag("NUMERICAL_DERIVATIVES", false, "calculate the derivatives for these quantities numerically"); 35 4328 : } 36 : 37 0 : void ActionWithValue::noAnalyticalDerivatives(Keywords& keys) { 38 0 : keys.remove("NUMERICAL_DERIVATIVES"); 39 0 : keys.addFlag("NUMERICAL_DERIVATIVES",false,"analytical derivatives are not implemented for this keyword so numerical derivatives are always used"); 40 0 : } 41 : 42 1194 : void ActionWithValue::componentsAreNotOptional(Keywords& keys) { 43 1194 : keys.setComponentsIntroduction("By default this Action calculates the following quantities. These quantities can " 44 : "be referenced elsewhere in the input by using this Action's label followed by a " 45 : "dot and the name of the quantity required from the list below."); 46 1194 : } 47 : 48 241 : void ActionWithValue::useCustomisableComponents(Keywords& keys) { 49 241 : keys.setComponentsIntroduction("The names of the components in this action can be customized by the user in the " 50 : "actions input file. However, in addition to the components that can be customized the " 51 : "following quantities will always be output"); 52 241 : } 53 : 54 4131 : ActionWithValue::ActionWithValue(const ActionOptions&ao): 55 : Action(ao), 56 4131 : noderiv(true), 57 4131 : numericalDerivatives(false) 58 : { 59 11924 : if( keywords.exists("NUMERICAL_DERIVATIVES") ) parseFlag("NUMERICAL_DERIVATIVES",numericalDerivatives); 60 4131 : if(numericalDerivatives) log.printf(" using numerical derivatives\n"); 61 4131 : } 62 : 63 4131 : ActionWithValue::~ActionWithValue() { 64 : // empty destructor to delete unique_ptr 65 4131 : } 66 : 67 1389822 : void ActionWithValue::clearInputForces() { 68 3470875 : for(unsigned i=0; i<values.size(); i++) values[i]->clearInputForce(); 69 1389822 : } 70 : 71 1392602 : void ActionWithValue::clearDerivatives() { 72 1392602 : unsigned nt = OpenMP::getNumThreads(); 73 1392602 : #pragma omp parallel num_threads(nt) 74 : { 75 : #pragma omp for 76 : for(unsigned i=0; i<values.size(); i++) values[i]->clearDerivatives(); 77 : } 78 1392602 : } 79 : 80 : // -- These are the routine for copying the value pointers to other classes -- // 81 : 82 10661051 : bool ActionWithValue::exists( const std::string& name ) const { 83 116533068 : for(unsigned i=0; i<values.size(); ++i) { 84 105897960 : if (values[i]->name==name) return true; 85 : } 86 : return false; 87 : } 88 : 89 26102 : Value* ActionWithValue::copyOutput( const std::string& name ) const { 90 11307760 : for(unsigned i=0; i<values.size(); ++i) { 91 11307760 : if (values[i]->name==name) return values[i].get(); 92 : } 93 0 : plumed_merror("there is no pointer with name " + name); 94 : } 95 : 96 10763 : Value* ActionWithValue::copyOutput( const unsigned& n ) const { 97 10763 : plumed_massert(n<values.size(),"you have requested a pointer that is out of bounds"); 98 10763 : return values[n].get(); 99 : } 100 : 101 : // -- HERE WE HAVE THE STUFF FOR THE DEFAULT VALUE -- // 102 : 103 56 : void ActionWithValue::addValue() { 104 56 : plumed_massert(values.empty(),"You have already added the default value for this action"); 105 56 : values.emplace_back(Tools::make_unique<Value>(this,getLabel(), false ) ); 106 56 : } 107 : 108 2317 : void ActionWithValue::addValueWithDerivatives() { 109 2317 : plumed_massert(values.empty(),"You have already added the default value for this action"); 110 2317 : values.emplace_back(Tools::make_unique<Value>(this,getLabel(), true ) ); 111 2317 : } 112 : 113 1697 : void ActionWithValue::setNotPeriodic() { 114 1697 : plumed_massert(values.size()==1,"The number of components is not equal to one"); 115 1697 : plumed_massert(values[0]->name==getLabel(), "The value you are trying to set is not the default"); 116 1697 : values[0]->min=0; values[0]->max=0; 117 1697 : values[0]->setupPeriodicity(); 118 1697 : } 119 : 120 676 : void ActionWithValue::setPeriodic( const std::string& min, const std::string& max ) { 121 676 : plumed_massert(values.size()==1,"The number of components is not equal to one"); 122 676 : plumed_massert(values[0]->name==getLabel(), "The value you are trying to set is not the default"); 123 676 : values[0]->setDomain( min, max ); 124 676 : } 125 : 126 16301774 : Value* ActionWithValue::getPntrToValue() { 127 : plumed_dbg_massert(values.size()==1,"The number of components is not equal to one"); 128 : plumed_dbg_massert(values[0]->name==getLabel(), "The value you are trying to retrieve is not the default"); 129 16301774 : return values[0].get(); 130 : } 131 : 132 : // -- HERE WE HAVE THE STUFF FOR NAMED VALUES / COMPONENTS -- // 133 : 134 22633 : void ActionWithValue::addComponent( const std::string& name ) { 135 22633 : if( !keywords.outputComponentExists(name,true) ) { 136 0 : plumed_merror("a description of component " + name + " has not been added to the manual. Components should be registered like keywords in " 137 : "registerKeywords as described in the developer docs."); 138 : } 139 45266 : std::string thename; thename=getLabel() + "." + name; 140 18683668 : for(unsigned i=0; i<values.size(); ++i) { 141 18661035 : plumed_massert(values[i]->name!=getLabel(),"Cannot mix single values with components"); 142 18661035 : plumed_massert(values[i]->name!=thename,"there is already a value with this name: "+thename); 143 18661035 : 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" 144 : "Remove the line addComponent(\"bias\") from your bias."); 145 : } 146 22633 : values.emplace_back(Tools::make_unique<Value>(this,thename, false ) ); 147 22633 : std::string msg=" added component to this action: "+thename+" \n"; 148 22633 : log.printf(msg.c_str()); 149 22633 : } 150 : 151 10710 : void ActionWithValue::addComponentWithDerivatives( const std::string& name ) { 152 10710 : if( !keywords.outputComponentExists(name,true) ) { 153 0 : plumed_merror("a description of component " + name + " has not been added to the manual. Components should be registered like keywords in " 154 : "registerKeywords as described in the developer doc."); 155 : } 156 21420 : std::string thename; thename=getLabel() + "." + name; 157 2441407 : for(unsigned i=0; i<values.size(); ++i) { 158 2430697 : plumed_massert(values[i]->name!=getLabel(),"Cannot mix single values with components"); 159 2430697 : plumed_massert(values[i]->name!=thename,"there is already a value with this name: "+thename); 160 2430697 : 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" 161 : "Remove the line addComponentWithDerivatives(\"bias\") from your bias."); 162 : } 163 10710 : values.emplace_back(Tools::make_unique<Value>(this,thename, true ) ); 164 10710 : std::string msg=" added component to this action: "+thename+" \n"; 165 10710 : log.printf(msg.c_str()); 166 10710 : } 167 : 168 10628297 : int ActionWithValue::getComponent( const std::string& name ) const { 169 10628297 : plumed_massert( !exists( getLabel() ), "You should not be calling this routine if you are using a value"); 170 21256594 : std::string thename; thename=getLabel() + "." + name; 171 64111312 : for(unsigned i=0; i<values.size(); ++i) { 172 64178768 : if (values[i]->name==thename) return i; 173 : } 174 0 : plumed_merror("there is no component with name " + name); 175 : } 176 : 177 0 : std::string ActionWithValue::getComponentsList( ) const { 178 : std::string complist; 179 0 : for(unsigned i=0; i<values.size(); ++i) { 180 0 : complist+=values[i]->name+" "; 181 : } 182 0 : return complist; 183 : } 184 : 185 1354 : std::vector<std::string> ActionWithValue::getComponentsVector( ) const { 186 : std::vector<std::string> complist; 187 220352 : for(unsigned i=0; i<values.size(); ++i) { 188 218998 : complist.push_back(values[i]->name); 189 : } 190 1354 : return complist; 191 0 : } 192 : 193 30152 : void ActionWithValue::componentIsNotPeriodic( const std::string& name ) { 194 30152 : int kk=getComponent(name); 195 30152 : values[kk]->min=0; values[kk]->max=0; 196 30152 : values[kk]->setupPeriodicity(); 197 30152 : } 198 : 199 92 : void ActionWithValue::componentIsPeriodic( const std::string& name, const std::string& min, const std::string& max ) { 200 92 : int kk=getComponent(name); 201 92 : values[kk]->setDomain(min,max); 202 92 : } 203 : 204 1389822 : void ActionWithValue::setGradientsIfNeeded() { 205 2779644 : if(isOptionOn("GRADIENTS")) { 206 366 : for(unsigned i=0; i<values.size(); i++) values[i]->setGradients(); 207 : } 208 1389822 : } 209 : 210 3493078 : void ActionWithValue::turnOnDerivatives() { 211 : // Turn on the derivatives 212 3493078 : noderiv=false; 213 : // Resize the derivatives 214 4106212105 : for(unsigned i=0; i<values.size(); ++i) values[i]->resizeDerivatives( getNumberOfDerivatives() ); 215 : // And turn on the derivatives in all actions on which we are dependent 216 7085574 : for(unsigned i=0; i<getDependencies().size(); ++i) { 217 3592496 : ActionWithValue* vv=dynamic_cast<ActionWithValue*>( getDependencies()[i] ); 218 3592496 : if(vv) vv->turnOnDerivatives(); 219 : } 220 3493078 : } 221 : 222 10598053 : Value* ActionWithValue::getPntrToComponent( const std::string& name ) { 223 10598053 : int kk=getComponent(name); 224 10598053 : return values[kk].get(); 225 : } 226 : 227 2139071 : Value* ActionWithValue::getPntrToComponent( int n ) { 228 : plumed_dbg_massert(n<values.size(),"you have requested a pointer that is out of bounds"); 229 2139071 : return values[n].get(); 230 : } 231 : 232 : }