LCOV - code coverage report
Current view: top level - core - ActionWithArguments.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 246 281 87.5 %
Date: 2026-11-05 10:19:04 Functions: 14 16 87.5 %

          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 "ActionWithArguments.h"
      23             : #include "ActionWithValue.h"
      24             : #include "ActionAtomistic.h"
      25             : #include "ActionForInterface.h"
      26             : #include "ActionWithVector.h"
      27             : #include "ActionWithVirtualAtom.h"
      28             : #include "ActionShortcut.h"
      29             : #include "tools/PDB.h"
      30             : #include "PlumedMain.h"
      31             : #include "ActionSet.h"
      32             : #include <iostream>
      33             : #include <regex>
      34             : 
      35             : namespace PLMD {
      36             : 
      37       22686 : void ActionWithArguments::registerKeywords(Keywords& keys) {
      38             : //  keys.reserve("numbered","ARG","the input for this action is the scalar output from one or more other actions. The particular scalars that you will use "
      39             : //               "are referenced using the label of the action. If the label appears on its own then it is assumed that the Action calculates "
      40             : //               "a single scalar value.  The value of this scalar is thus used as the input to this new action.  If * or *.* appears the "
      41             : //               "scalars calculated by all the proceeding actions in the input file are taken.  Some actions have multi-component outputs and "
      42             : //               "each component of the output has a specific label.  For example a \\ref DISTANCE action labelled dist may have three components "
      43             : //               "x, y and z.  To take just the x component you should use dist.x, if you wish to take all three components then use dist.*."
      44             : //               "More information on the referencing of Actions can be found in the section of the manual on the PLUMED \\ref Syntax.  "
      45             : //               "Scalar values can also be "
      46             : //               "referenced using POSIX regular expressions as detailed in the section on \\ref Regex. To use this feature you you must compile "
      47             : //               "PLUMED with the appropriate flag.");
      48       22686 : }
      49             : 
      50       16202 : void ActionWithArguments::parseArgumentList(const std::string&key,std::vector<Value*>&arg) {
      51       32404 :   if( keywords.getArgumentType(key).length()==0 ) {
      52          72 :     warning("keyword " + key + " for reading arguments is registered using Keyword::add rather than Keyword::addInputKeyword.  The keyword will thus not appear in the correct place in the manual");
      53             :   }
      54             :   std::string def;
      55       16202 :   std::vector<std::string> c;
      56       16202 :   arg.clear();
      57       16202 :   parseVector(key,c);
      58       23463 :   if( c.size()==0 && (keywords.style(key,"compulsory") || keywords.style(key,"hidden")) ) {
      59           8 :     if( keywords.getDefaultValue(key,def) ) {
      60           0 :       c.push_back( def );
      61             :     } else {
      62             :       return;
      63             :     }
      64             :   }
      65       16194 :   interpretArgumentList(c,plumed.getActionSet(),this,arg);
      66       16202 : }
      67             : 
      68         183 : bool ActionWithArguments::parseArgumentList(const std::string&key,int i,std::vector<Value*>&arg) {
      69         366 :   if( keywords.getArgumentType(key).length()==0 ) {
      70           0 :     warning("keyword " + key + " for reading argument is registered using Keyword::add rather than Keyword::addInputKeyword.  The keyword will thus not appear in the correct place in the manual");
      71             :   }
      72         183 :   std::vector<std::string> c;
      73         183 :   arg.clear();
      74         183 :   if(parseNumberedVector(key,i,c)) {
      75          67 :     interpretArgumentList(c,plumed.getActionSet(),this,arg);
      76             :     return true;
      77             :   } else {
      78             :     return false;
      79             :   }
      80         183 : }
      81             : 
      82             : // True if readact cannot use v because not all the elements of v are computed (the action that computes v uses a mask)
      83       40582 : static bool maskedValueNotAllowed( const Action* readact, Value* v ) {
      84       40582 :   if( v->getRank()==0 ) {
      85             :     return false;
      86             :   }
      87        2373 :   if( readact->keywords.exists("MASKED_INPUT_ALLOWED") || readact->keywords.exists("IS_SHORTCUT") || readact->keywords.exists("MASK") ) {
      88           0 :     return false;
      89             :   }
      90        2373 :   ActionWithVector* av=dynamic_cast<ActionWithVector*>( v->getPntrToAction() );
      91        2373 :   return av && av->getNumberOfMasks()>=0;
      92             : }
      93             : 
      94       21898 : void ActionWithArguments::interpretArgumentList(const std::vector<std::string>& c, const ActionSet& as, Action* readact, std::vector<Value*>&arg) {
      95             :   // ARG=* and ARG=*.* take the values of all the actions, including the ones that the shortcuts create.
      96             :   // The values that this action cannot use (a type it does not accept, or a vector of which only some elements
      97             :   // are computed, e.g. the strand pairs of PARABETARMSD with STRANDS_CUTOFF) are left out, so that e.g.
      98             :   // PRINT ARG=* works as in previous versions.
      99       21898 :   unsigned nskipped=0;
     100         762 :   auto addFromWildcard=[&]( Value* v ) {
     101         762 :     if( !readact->keywords.checkArgumentType( v->getRank(), v->hasDerivatives() ) || maskedValueNotAllowed( readact, v ) ) {
     102           4 :       nskipped++;
     103           4 :       return;
     104             :     }
     105         758 :     arg.push_back(v);
     106       21898 :   };
     107       53531 :   for(unsigned i=0; i<c.size(); i++) {
     108             :     // is a regex? then just interpret it. The signal is ()
     109       31636 :     if(!c[i].compare(0,1,"(")) {
     110         251 :       unsigned l=c[i].length();
     111         251 :       if(!c[i].compare(l-1,1,")")) {
     112             :         // start regex parsing
     113             :         bool found_something=false;
     114             :         // take the string enclosed in quotes and put in round brackets
     115         250 :         std::string myregex=c[i];
     116         250 :         std::vector<ActionWithValue*> all=as.select<ActionWithValue*>();
     117         250 :         if( all.empty() ) {
     118           1 :           readact->error("your input file is not telling plumed to calculate anything");
     119             :         }
     120             : 
     121             :         try {
     122         250 :           std::regex txt_regex(myregex,std::regex::extended);
     123         249 :           plumed_massert(txt_regex.mark_count()==1,"I can parse with only one subexpression");
     124       24618 :           for(unsigned j=0; j<all.size(); j++) {
     125       24369 :             std::vector<std::string> ss=all[j]->getComponentsVector();
     126      352871 :             for(unsigned  k=0; k<ss.size(); ++k) {
     127      328502 :               if(std::regex_match(ss[k],txt_regex)) {
     128       21994 :                 arg.push_back(all[j]->copyOutput(ss[k]));
     129             :                 found_something=true;
     130             :               }
     131             :             }
     132       24369 :           }
     133         250 :         } catch(std::regex_error & e) {
     134           3 :           plumed_error()<<"Error parsing regular expression: "<<e.what();
     135           1 :         }
     136         249 :         if(!found_something) {
     137           0 :           plumed_error()<<"There isn't any action matching your regex " << myregex;
     138             :         }
     139             :       } else {
     140           2 :         plumed_merror("did you want to use regexp to input arguments? enclose it between two round braces (...) with no spaces!");
     141             :       }
     142             :     } else {
     143             :       std::size_t dot=c[i].find_first_of('.');
     144       31385 :       std::string a=c[i].substr(0,dot);
     145       31385 :       std::string name=c[i].substr(dot+1);
     146       31385 :       if(c[i].find(".")!=std::string::npos) {   // if it contains a dot:
     147        9531 :         if(a=="*" && name=="*") {
     148             :           // Take all values from all actions
     149           1 :           std::vector<ActionWithValue*> all=as.select<ActionWithValue*>();
     150           1 :           if( all.empty() ) {
     151           0 :             readact->error("your input file is not telling plumed to calculate anything");
     152             :           }
     153          17 :           for(unsigned j=0; j<all.size(); j++) {
     154          16 :             plumed_assert(all[j]); // needed for following calls, see #1046
     155          16 :             ActionForInterface* ap=all[j]->castToActionForInterface();
     156          16 :             if( ap ) {
     157           8 :               continue;
     158             :             }
     159          18 :             for(unsigned k=0; k<all[j]->getNumberOfComponents(); ++k) {
     160          10 :               addFromWildcard(all[j]->copyOutput(k));
     161             :             }
     162             :           }
     163        9530 :         } else if ( name=="*") {
     164             :           unsigned carg=arg.size();
     165             :           // Take all the values from an action with a specific name
     166         778 :           ActionShortcut* shortcut=as.getShortcutActionWithLabel(a);
     167         778 :           if( shortcut ) {
     168         952 :             shortcut->interpretDataLabel( a + "." + name, readact, arg );
     169             :           }
     170         778 :           if( arg.size()==carg ) {
     171             :             // Take all the values from an action with a specific name
     172         517 :             ActionWithValue* action=as.selectWithLabel<ActionWithValue*>(a);
     173         517 :             if(!action) {
     174           0 :               std::string str=" (hint! the actions with value in this ActionSet are: ";
     175           0 :               str+=as.getLabelList<ActionWithValue*>()+")";
     176           0 :               readact->error("cannot find action named " + a + str);
     177             :             }
     178         517 :             if( action->getNumberOfComponents()==0 ) {
     179           0 :               readact->error("found " + a +".* indicating use all components calculated by action with label " + a + " but this action has no components");
     180             :             }
     181        7773 :             for(unsigned k=0; k<action->getNumberOfComponents(); ++k) {
     182        7256 :               arg.push_back(action->copyOutput(k));
     183             :             }
     184             :           }
     185        8752 :         } else if ( a=="*" ) {
     186          17 :           std::vector<ActionShortcut*> shortcuts=as.select<ActionShortcut*>();
     187             :           // Take components from all actions with a specific name
     188          17 :           std::vector<ActionWithValue*> all=as.select<ActionWithValue*>();
     189          17 :           if( all.empty() ) {
     190           0 :             readact->error("your input file is not telling plumed to calculate anything");
     191             :           }
     192             :           unsigned carg=arg.size();
     193         171 :           for(unsigned j=0; j<shortcuts.size(); ++j) {
     194         308 :             shortcuts[j]->interpretDataLabel( shortcuts[j]->getShortcutLabel() + "." + name, readact, arg );
     195             :           }
     196             :           unsigned nval=0;
     197         333 :           for(unsigned j=0; j<all.size(); j++) {
     198             :             std::string flab;
     199         632 :             flab=all[j]->getLabel() + "." + name;
     200         316 :             if( all[j]->exists(flab) ) {
     201          44 :               arg.push_back(all[j]->copyOutput(flab));
     202          44 :               nval++;
     203             :             }
     204             :           }
     205          17 :           if(nval==0 && arg.size()==carg) {
     206           0 :             readact->error("found no actions with a component called " + name );
     207             :           }
     208             :         } else {
     209             :           // Take values with a specific name
     210        8735 :           ActionWithValue* action=as.selectWithLabel<ActionWithValue*>(a);
     211        8735 :           ActionShortcut* shortcut=as.getShortcutActionWithLabel(a);
     212        8735 :           if( !shortcut && !action ) {
     213           0 :             std::string str=" (hint! the actions with value in this ActionSet are: ";
     214           0 :             str+=as.getLabelList<ActionWithValue*>()+")";
     215           0 :             readact->error("cannot find action named " + a +str);
     216        8735 :           } else if( action && action->exists(c[i]) ) {
     217        8621 :             arg.push_back(action->copyOutput(c[i]));
     218         114 :           } else if( shortcut ) {
     219             :             unsigned narg=arg.size();
     220         228 :             shortcut->interpretDataLabel( a + "." + name, readact, arg );
     221         114 :             if( arg.size()==narg ) {
     222           0 :               readact->error("found no element in " + a + " with label " + name );
     223             :             }
     224             :           } else {
     225           0 :             std::string str=" (hint! the components in this actions are: ";
     226           0 :             str+=action->getComponentsList()+")";
     227           0 :             readact->error("action " + a + " has no component named " + name + str);
     228             :           }
     229             :         }
     230             :       } else {    // if it doesn't contain a dot
     231       21854 :         if(c[i]=="*") {
     232             :           // Take all values from all actions
     233         113 :           std::vector<ActionWithValue*> all=as.select<ActionWithValue*>();
     234         113 :           if( all.empty() ) {
     235           0 :             readact->error("your input file is not telling plumed to calculate anything");
     236             :           }
     237        1711 :           for(unsigned j=0; j<all.size(); j++) {
     238        1598 :             plumed_assert(all[j]); // needed for following calls, see #1046
     239        1598 :             ActionWithVirtualAtom* av=all[j]->castToActionWithVirtualAtom();
     240        1598 :             if( av ) {
     241          57 :               continue;
     242             :             }
     243        1541 :             ActionForInterface* ap=all[j]->castToActionForInterface();
     244        1541 :             if( ap && all[j]->getName()!="ENERGY" ) {
     245         882 :               continue;
     246             :             }
     247        1411 :             for(unsigned k=0; k<all[j]->getNumberOfComponents(); ++k) {
     248         752 :               addFromWildcard(all[j]->copyOutput(k));
     249             :             }
     250             :           }
     251             :         } else {
     252       21741 :           ActionWithValue* action=as.selectWithLabel<ActionWithValue*>(c[i]);
     253       21741 :           if(!action) {
     254           1 :             std::string str=" (hint! the actions with value in this ActionSet are: ";
     255           1 :             str+=as.getLabelList<ActionWithValue*>()+")";
     256           2 :             readact->error("cannot find action named " + c[i] + str );
     257             :           }
     258       21740 :           if( !(action->exists(c[i])) ) {
     259           0 :             std::string str=" (hint! the components in this actions are: ";
     260           0 :             str+=action->getComponentsList()+")";
     261           0 :             readact->error("action " + c[i] + " has no component named " + c[i] +str);
     262             :           };
     263       21741 :           arg.push_back(action->copyOutput(c[i]));
     264             :         }
     265             :       }
     266             :     }
     267             :   }
     268       21895 :   if( nskipped>0 ) {
     269           1 :     readact->log.printf("  %u values selected with * are not used: this action cannot use their type, or not all their elements are computed\n", nskipped);
     270             :   }
     271       82744 :   for(unsigned i=0; i<arg.size(); ++i) {
     272       60850 :     if( !readact->keywords.checkArgumentType( arg[i]->getRank(), arg[i]->hasDerivatives() ) ) {
     273             :       std::string type;
     274           1 :       if( arg[i]->getRank()>0 && arg[i]->hasDerivatives() ) {
     275             :         type = "function on a grid";
     276           1 :       } else if( arg[i]->getRank()==0 ) {
     277             :         type = "scalar";
     278           1 :       } else if( arg[i]->getRank()==1 ) {
     279             :         type = "vector";
     280           0 :       } else if( arg[i]->getRank()==2 ) {
     281             :         type = "matrix";
     282             :       } else {
     283           1 :         type = "value of rank " + std::to_string(arg[i]->getRank());
     284             :       }
     285             :       std::string accepted;
     286           2 :       for(const auto & kw : readact->keywords.getArgumentKeys() ) {
     287           3 :         accepted += " " + kw + " (" + readact->keywords.getArgumentType(kw) + ")";
     288           1 :       }
     289           5 :       readact->error("argument " + arg[i]->getName() + " is a " + type + ", which is not accepted by " + readact->getName() + ". Accepted types:" + accepted );
     290             :     }
     291             :   }
     292       21894 :   if( readact->keywords.exists("MASKED_INPUT_ALLOWED") || readact->keywords.exists("IS_SHORTCUT") || readact->keywords.exists("MASK") ) {
     293       14608 :     return;
     294             :   }
     295       47106 :   for(unsigned i=0; i<arg.size(); ++i) {
     296       39820 :     if( maskedValueNotAllowed( readact, arg[i] ) ) {
     297           0 :       readact->error("cannot use argument " + arg[i]->getName() + " in input as not all elements are computed");
     298             :     }
     299             :   }
     300             : }
     301             : 
     302           0 : void ActionWithArguments::expandArgKeywordInPDB( const PDB& pdb ) {
     303           0 :   std::vector<std::string> arg_names = pdb.getArgumentNames();
     304           0 :   if( arg_names.size()>0 ) {
     305           0 :     std::vector<Value*> arg_vals;
     306           0 :     interpretArgumentList( arg_names, plumed.getActionSet(), this, arg_vals );
     307             :   }
     308           0 : }
     309             : 
     310       13478 : void ActionWithArguments::requestArguments(const std::vector<Value*> &arg) {
     311       13478 :   plumed_massert(!lockRequestArguments,"requested argument list can only be changed in the prepare() method");
     312       13478 :   arguments=arg;
     313       13478 :   clearDependencies();
     314             :   std::string fullname;
     315             :   std::string argName;
     316       57792 :   for(unsigned i=0; i<arguments.size(); i++) {
     317       44314 :     fullname=arguments[i]->getName();
     318       44314 :     if(fullname.find(".")!=std::string::npos) {
     319             :       std::size_t dot=fullname.find_first_of('.');
     320       52616 :       argName=fullname.substr(0,dot);
     321             :     } else {
     322             :       argName=fullname;
     323             :     }
     324       44314 :     ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(argName);
     325       44314 :     plumed_massert(action,"cannot find action named (in requestArguments - this is weird)" + argName);
     326       44314 :     addDependency(action);
     327             :   }
     328       13478 :   ActionWithValue* av=dynamic_cast<ActionWithValue*>(this);
     329       13478 :   if(av) {
     330         950 :     av->firststep=true;
     331             :   }
     332       13478 : }
     333             : 
     334          38 : void ActionWithArguments::requestExtraDependencies(const std::vector<Value*> &extra) {
     335          38 :   plumed_massert(!lockRequestArguments,"requested argument list can only be changed in the prepare() method");
     336             :   std::string fullname;
     337             :   std::string argName;
     338          77 :   for(unsigned i=0; i<extra.size(); i++) {
     339          39 :     fullname=extra[i]->getName();
     340          39 :     if(fullname.find(".")!=std::string::npos) {
     341             :       std::size_t dot=fullname.find_first_of('.');
     342          64 :       argName=fullname.substr(0,dot);
     343             :     } else {
     344             :       argName=fullname;
     345             :     }
     346          39 :     ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(argName);
     347          39 :     plumed_massert(action,"cannot find action named (in requestArguments - this is weird)" + argName);
     348          39 :     addDependency(action);
     349             :   }
     350          38 : }
     351             : 
     352       13409 : ActionWithArguments::ActionWithArguments(const ActionOptions&ao):
     353             :   Action(ao),
     354       13409 :   lockRequestArguments(false) {
     355       13410 :   if( keywords.exists("ARG") ) {
     356       12517 :     std::vector<Value*> arg;
     357       25033 :     parseArgumentList("ARG",arg);
     358             : 
     359       12516 :     if(!arg.empty()) {
     360       12057 :       log.printf("  with arguments : \n");
     361       53747 :       for(unsigned i=0; i<arg.size(); i++) {
     362       41690 :         if( arg[i]->hasDerivatives() && arg[i]->getRank()>0 ) {
     363         446 :           log.printf(" function on grid with label %s \n",arg[i]->getName().c_str());
     364       41244 :         } else if( arg[i]->getRank()==2 ) {
     365        2877 :           log.printf("   matrix with label %s \n",arg[i]->getName().c_str());
     366       38367 :         } else if( arg[i]->getRank()==1 ) {
     367        6846 :           log.printf("   vector with label %s \n",arg[i]->getName().c_str());
     368       31521 :         } else if( arg[i]->getRank()==0 ) {
     369       31521 :           log.printf("   scalar with label %s \n",arg[i]->getName().c_str());
     370             :         } else {
     371           1 :           error("type of argument does not make sense");
     372             :         }
     373             :       }
     374             :     }
     375       12516 :     requestArguments(arg);
     376             :   }
     377       13408 : }
     378             : 
     379          58 : void ActionWithArguments::calculateNumericalDerivatives( ActionWithValue* a ) {
     380          58 :   if(!a) {
     381          58 :     a=castToActionWithValue();
     382          58 :     plumed_massert(a,"cannot compute numerical derivatives for an action without values");
     383             :   }
     384             : 
     385             :   const size_t nval=a->getNumberOfComponents();
     386             :   const size_t npar=arguments.size();
     387          58 :   std::vector<double> value (nval*npar);
     388         161 :   for(unsigned i=0; i<npar; i++) {
     389         103 :     double arg0=arguments[i]->get();
     390         103 :     arguments[i]->set(arg0+std::sqrt(epsilon));
     391         103 :     a->calculate();
     392         103 :     arguments[i]->set(arg0);
     393        1367 :     for(unsigned j=0; j<nval; j++) {
     394        1264 :       value[i*nval+j]=a->getOutputQuantity(j);
     395             :     }
     396             :   }
     397          58 :   a->calculate();
     398          58 :   a->clearDerivatives();
     399        1192 :   for(unsigned j=0; j<nval; j++) {
     400        1134 :     Value* v=a->copyOutput(j);
     401        1134 :     if( v->hasDerivatives() )
     402         286 :       for(unsigned i=0; i<npar; i++) {
     403         208 :         v->addDerivative(i,(value[i*nval+j]-a->getOutputQuantity(j))/std::sqrt(epsilon));
     404             :       }
     405             :   }
     406          58 : }
     407             : 
     408        3048 : double ActionWithArguments::getProjection(unsigned i,unsigned j)const {
     409        3048 :   plumed_massert(i<arguments.size()," making projections with an index which  is too large");
     410        3048 :   plumed_massert(j<arguments.size()," making projections with an index which  is too large");
     411        3048 :   const Value* v1=arguments[i];
     412        3048 :   const Value* v2=arguments[j];
     413        3048 :   return Value::projection(*v1,*v2);
     414             : }
     415             : 
     416      230728 : void ActionWithArguments::addForcesOnArguments( const unsigned& argstart, const std::vector<double>& forces, unsigned& ind ) {
     417      230728 :   unsigned nargs=arguments.size();
     418      230728 :   const ActionWithVector* av=dynamic_cast<const ActionWithVector*>( this );
     419      230728 :   if( av && av->getNumberOfMasks()>0 ) {
     420        1088 :     nargs=nargs-av->getNumberOfMasks();
     421             :   }
     422      542911 :   for(unsigned i=0; i<nargs; ++i) {
     423      312183 :     ind += arguments[i]->addForces(View(&forces[ind],forces.size()-ind));
     424             :   }
     425      230728 : }
     426             : 
     427        1672 : void ActionWithArguments::setGradients( Value* myval, unsigned& start ) const {
     428        1672 :   if( !myval->hasDeriv ) {
     429             :     return;
     430             :   }
     431        1012 :   plumed_assert( myval->getRank()==0 );
     432             : 
     433             :   bool scalar=true;
     434        3145 :   for(unsigned i=0; i<arguments.size(); ++i ) {
     435        2133 :     if( arguments[i]->getRank()!=0 ) {
     436             :       scalar=false;
     437             :       break;
     438             :     }
     439             :   }
     440        1012 :   if( !scalar ) {
     441             :     bool constant=true;
     442           0 :     for(unsigned i=0; i<arguments.size(); ++i ) {
     443           0 :       if( !arguments[i]->isConstant() ) {
     444             :         constant=false;
     445             :         break;
     446             :       } else {
     447           0 :         start += arguments[i]->getNumberOfValues();
     448             :       }
     449             :     }
     450           0 :     if( !constant ) {
     451           0 :       error("cannot set gradient as unable to handle non-constant actions that take vectors/matrices/grids in input");
     452             :     }
     453             :   }
     454             :   // Now pass the gradients
     455        3145 :   for(unsigned i=0; i<arguments.size(); ++i ) {
     456        2133 :     arguments[i]->passGradients( myval->getDerivative(i), myval->gradients );
     457             :   }
     458             : }
     459             : 
     460       24705 : bool ActionWithArguments::calculateConstantValues( const bool& haveatoms ) {
     461       24705 :   ActionWithValue* awval = castToActionWithValue();
     462       24705 :   if( !awval || arguments.size()==0 ) {
     463             :     return false;
     464             :   }
     465             :   bool constant = true, atoms=false;
     466       19449 :   for(unsigned i=0; i<arguments.size(); ++i) {
     467       19126 :     auto * ptr=arguments[i]->getPntrToAction();
     468       19126 :     plumed_assert(ptr); // needed for following calls, see #1046
     469       19126 :     ActionAtomistic* aa=ptr->castToActionAtomistic();
     470       19126 :     if( aa ) {
     471       12765 :       ActionWithVector* awvec=dynamic_cast<ActionWithVector*>( arguments[i]->getPntrToAction() );
     472       12765 :       if( !awvec || aa->getNumberOfAtoms()>0 ) {
     473             :         atoms=true;
     474             :       }
     475             :     }
     476       19126 :     if( !arguments[i]->isConstant() ) {
     477             :       constant=false;
     478             :       break;
     479             :     }
     480             :   }
     481       18631 :   if( constant ) {
     482             :     // Set everything constant first as we need to set the shape
     483         670 :     for(unsigned i=0; i<awval->getNumberOfComponents(); ++i) {
     484         347 :       (awval->copyOutput(i))->setConstant();
     485             :     }
     486         323 :     if( !haveatoms ) {
     487         305 :       log.printf("  values stored by this action are computed during startup and stay fixed during the simulation\n");
     488             :     }
     489         323 :     if( atoms ) {
     490          36 :       return haveatoms;
     491             :     }
     492             :   }
     493             :   // Now do the calculation and store the values if we don't need anything from the atoms
     494         287 :   if( constant && !haveatoms ) {
     495             :     plumed_assert( !atoms );
     496         287 :     activate();
     497         287 :     calculate();
     498         287 :     deactivate();
     499         598 :     for(unsigned i=0; i<awval->getNumberOfComponents(); ++i) {
     500         311 :       unsigned nv = awval->copyOutput(i)->getNumberOfValues();
     501         311 :       log.printf("  %d values stored in component labelled %s are : ", nv, (awval->copyOutput(i))->getName().c_str() );
     502        6789 :       for(unsigned j=0; j<nv; ++j) {
     503        6478 :         log.printf(" %f", (awval->copyOutput(i))->get(j) );
     504             :       }
     505         311 :       log.printf("\n");
     506             :     }
     507             :   }
     508             :   return constant;
     509             : }
     510             : 
     511             : }

Generated by: LCOV version 1.16