LCOV - code coverage report
Current view: top level - core - ActionWithValue.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 121 134 90.3 %
Date: 2026-03-30 13:16:06 Functions: 25 30 83.3 %

          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             : }

Generated by: LCOV version 1.16