LCOV - code coverage report
Current view: top level - core - Action.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 197 239 82.4 %
Date: 2026-03-30 11:13:23 Functions: 32 38 84.2 %

          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 "Action.h"
      23             : #include "ActionAtomistic.h"
      24             : #include "ActionWithValue.h"
      25             : #include "ActionWithArguments.h"
      26             : #include "ActionWithVirtualAtom.h"
      27             : #include "ActionForInterface.h"
      28             : #include "DomainDecomposition.h"
      29             : #include "PbcAction.h"
      30             : #include "ActionToPutData.h"
      31             : #include "ActionToGetData.h"
      32             : #include "PlumedMain.h"
      33             : #include "tools/Log.h"
      34             : #include "tools/Exception.h"
      35             : #include "tools/Communicator.h"
      36             : #include "ActionSet.h"
      37             : #include <iostream>
      38             : 
      39             : namespace PLMD {
      40             : 
      41             : Keywords ActionOptions::emptyKeys;
      42             : 
      43       51076 : ActionOptions::ActionOptions(PlumedMain&p,const std::vector<std::string>&l):
      44       51076 :   plumed(p),
      45       51076 :   line(l),
      46       51076 :   keys(emptyKeys) {
      47       51076 : }
      48             : 
      49       51074 : ActionOptions::ActionOptions(const ActionOptions&ao,const Keywords&keys):
      50       51074 :   plumed(ao.plumed),
      51       51074 :   line(ao.line),
      52       51074 :   keys(keys) {
      53       51074 : }
      54             : 
      55       74713 : void Action::registerKeywords( Keywords& keys ) {
      56       74713 :   plumed_assert( keys.size()==0 );
      57      149426 :   keys.add( "hidden", "LABEL", "a label for the action so that its output can be referenced in the input to other actions.  Actions with scalar output are referenced using their label only.  Actions with vector output must have a separate label for every component.  Individual components are then referred to using label.component" );
      58      149426 :   keys.reserve("optional","UPDATE_FROM","Only update this action from this time");
      59      149426 :   keys.reserve("optional","UPDATE_UNTIL","Only update this action until this time");
      60      149426 :   keys.reserve("optional","RESTART","allows per-action setting of restart (YES/NO/AUTO)");
      61       74713 : }
      62             : 
      63       51074 : Action::Action(const ActionOptions&ao):
      64       51074 :   name(ao.line[0]),
      65       51074 :   line(ao.line),
      66       51074 :   update_from(std::numeric_limits<double>::max()),
      67       51074 :   update_until(std::numeric_limits<double>::max()),
      68       51074 :   timestep(0),
      69       51074 :   active(false),
      70       51074 :   restart(ao.plumed.getRestart()),
      71       51074 :   doCheckPoint(ao.plumed.getCPT()),
      72       51074 :   never_activate(name=="CONSTANT"),
      73       51074 :   plumed(ao.plumed),
      74       51074 :   log(plumed.getLog()),
      75       51074 :   comm(plumed.comm),
      76       51074 :   multi_sim_comm(plumed.multi_sim_comm),
      77      102148 :   keywords(ao.keys) {
      78             :   // Retrieve the timestep and save it
      79       51074 :   resetStoredTimestep();
      80             : 
      81             :   line.erase(line.begin());
      82      102148 :   if( !keywords.exists("NO_ACTION_LOG") ) {
      83       35411 :     log.printf("Action %s\n",name.c_str());
      84       35411 :     if(ao.fullPath.length()>0) {
      85          41 :       log<<"  from library: "<<ao.fullPath<<"\n";
      86             :     }
      87             :   }
      88             : 
      89       51074 :   if(comm.Get_rank()==0) {
      90       37125 :     replica_index=multi_sim_comm.Get_rank();
      91             :   }
      92       51074 :   comm.Bcast(replica_index,0);
      93             : 
      94      102148 :   if ( keywords.exists("LABEL") ) {
      95      101682 :     parse("LABEL",label);
      96             :   }
      97       51074 :   if(label.length()==0) {
      98             :     std::string s;
      99        3241 :     Tools::convert(plumed.getActionSet().size()-plumed.getActionSet().select<ActionForInterface*>().size(),s);
     100        6482 :     label="@"+s;
     101       47833 :   } else if ( label.find(".")!=std::string::npos ) {
     102          12 :     warning("using full stop in an action label should be avaoided as . has a special meaning in PLUMED action labels");
     103             :   }
     104       51074 :   if( plumed.getActionSet().selectWithLabel<Action*>(label) ) {
     105           0 :     error("label " + label + " has been already used");
     106             :   }
     107      102148 :   if( !keywords.exists("NO_ACTION_LOG") ) {
     108       35411 :     log.printf("  with label %s\n",label.c_str());
     109             :   }
     110      102148 :   if ( keywords.exists("UPDATE_FROM") ) {
     111        4586 :     parse("UPDATE_FROM",update_from);
     112             :   }
     113      102148 :   if( !keywords.exists("NO_ACTION_LOG") && update_from!=std::numeric_limits<double>::max()) {
     114           5 :     log.printf("  only update from time %f\n",update_from);
     115             :   }
     116      102148 :   if ( keywords.exists("UPDATE_UNTIL") ) {
     117        4586 :     parse("UPDATE_UNTIL",update_until);
     118             :   }
     119      102148 :   if( !keywords.exists("NO_ACTION_LOG") && update_until!=std::numeric_limits<double>::max()) {
     120           5 :     log.printf("  only update until time %f\n",update_until);
     121             :   }
     122      102148 :   if ( keywords.exists("RESTART") ) {
     123        2258 :     std::string srestart="AUTO";
     124        2257 :     parse("RESTART",srestart);
     125        2257 :     if( plumed.parseOnlyMode() ) {
     126           0 :       restart=false;
     127        2257 :     } else if(srestart=="YES") {
     128         170 :       restart=true;
     129        2087 :     } else if(srestart=="NO") {
     130          22 :       restart=false;
     131        2065 :     } else if(srestart=="AUTO") {
     132             :       // do nothing, this is the default
     133             :     } else {
     134           2 :       error("RESTART should be either YES, NO, or AUTO");
     135             :     }
     136             :   }
     137       51074 : }
     138             : 
     139      100628 : void Action::resetStoredTimestep() {
     140      100628 :   ActionWithValue* ts = plumed.getActionSet().selectWithLabel<ActionWithValue*>("timestep");
     141      100628 :   if( ts ) {
     142       94341 :     timestep = (ts->copyOutput(0))->get();
     143             :   }
     144      100628 : }
     145             : 
     146      102146 : Action::~Action() {
     147       51073 :   if(files.size()!=0) {
     148           0 :     std::cerr<<"WARNING: some files open in action "+getLabel()+" where not properly closed. This could lead to data loss!!\n";
     149             :   }
     150      102146 : }
     151             : 
     152          82 : FILE* Action::fopen(const char *path, const char *mode) {
     153             :   bool write(false);
     154         164 :   for(const char*p=mode; *p; p++)
     155          82 :     if(*p=='w' || *p=='a' || *p=='+') {
     156             :       write=true;
     157             :     }
     158             :   FILE* fp;
     159          82 :   if(write && comm.Get_rank()!=0) {
     160           0 :     fp=plumed.fopen("/dev/null",mode);
     161             :   } else {
     162          82 :     fp=plumed.fopen(path,mode);
     163             :   }
     164          81 :   files.insert(fp);
     165          81 :   return fp;
     166             : }
     167             : 
     168          99 : int Action::fclose(FILE*fp) {
     169             :   files.erase(fp);
     170          99 :   return plumed.fclose(fp);
     171             : }
     172             : 
     173       60948 : void Action::fflush() {
     174       60948 :   for(const auto & p : files) {
     175           0 :     std::fflush(p);
     176             :   }
     177       60948 : }
     178             : 
     179           0 : std::string Action::getKeyword(const std::string& key) {
     180             :   // Check keyword has been registered
     181           0 :   plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered");
     182             : 
     183             :   std::string outkey;
     184           0 :   if( Tools::getKey(line,key,outkey ) ) {
     185           0 :     return key + outkey;
     186             :   }
     187             : 
     188           0 :   if( keywords.style(key,"compulsory") ) {
     189           0 :     if( keywords.getDefaultValue(key,outkey) ) {
     190           0 :       if( outkey.length()==0 ) {
     191           0 :         error("keyword " + key + " has weird default value");
     192             :       }
     193           0 :       return key + "=" +  outkey;
     194             :     } else {
     195           0 :       error("keyword " + key + " is compulsory for this action");
     196             :     }
     197             :   }
     198           0 :   return "";
     199             : }
     200             : 
     201       95720 : void Action::parseFlag(const std::string&key,bool & t) {
     202             :   // Check keyword has been registered
     203       95720 :   plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered");
     204             :   // Check keyword is a flag
     205      191440 :   if(!keywords.style(key,"nohtml")) {
     206      191440 :     plumed_massert( keywords.style(key,"vessel") || keywords.style(key,"flag") || keywords.style(key,"hidden"), "keyword " + key + " is not a flag");
     207             :   }
     208             : 
     209             :   // Read in the flag otherwise get the default value from the keywords object
     210       95720 :   if(!Tools::parseFlag(line,key,t)) {
     211      167330 :     if( keywords.style(key,"nohtml") || keywords.style(key,"vessel") ) {
     212           0 :       t=false;
     213       83665 :     } else if ( !keywords.getLogicalDefault(key,t) ) {
     214           0 :       log.printf("ERROR in action %s with label %s : flag %s has no default",name.c_str(),label.c_str(),key.c_str() );
     215           0 :       plumed_error();
     216             :     }
     217             :   }
     218       95720 : }
     219             : 
     220     1262985 : void Action::addDependency(Action*action) {
     221             :   bool found=false;
     222    40065368 :   for(const auto & d : after ) {
     223    39065475 :     if( action==d ) {
     224             :       found=true;
     225             :       break;
     226             :     }
     227             :   }
     228     1262985 :   if( !found ) {
     229      999893 :     after.push_back(action);
     230             :   }
     231     1262985 : }
     232             : 
     233      571383 : bool Action::checkForDependency( Action* action ) {
     234     1124757 :   for(const auto & d : after) {
     235      563943 :     if( action==d ) {
     236             :       return true;
     237             :     }
     238      557562 :     if( d->checkForDependency(action) ) {
     239             :       return true;
     240             :     }
     241             :   }
     242             :   return false;
     243             : }
     244             : 
     245     5247017 : void Action::activate() {
     246             : // This is set to true if actions are only need to be computed in setup (during checkRead)
     247     5247017 :   if( never_activate ) {
     248             :     return;
     249             :   }
     250             : // preparation step is called only the first time an Action is activated.
     251             : // since it could change its dependences (e.g. in an ActionAtomistic which is
     252             : // accessing to a virtual atom), this is done just before dependencies are
     253             : // activated
     254     5132651 :   if(!active) {
     255     2649962 :     this->unlockRequests();
     256     2649962 :     prepare();
     257     2649962 :     this->lockRequests();
     258             :   } else {
     259             :     return;
     260             :   }
     261     6545184 :   for(const auto & p : after) {
     262     3895222 :     p->activate();
     263             :   }
     264     2649962 :   active=true;
     265             : }
     266             : 
     267        2228 : void Action::setOption(const std::string &s) {
     268             : // This overloads the action and activate some options
     269        2228 :   options.insert(s);
     270        4370 :   for(const auto & p : after) {
     271        2142 :     p->setOption(s);
     272             :   }
     273        2228 : }
     274             : 
     275           0 : void Action::clearOptions() {
     276             : // This overloads the action and activate some options
     277             :   options.clear();
     278           0 : }
     279             : 
     280             : 
     281      199562 : void Action::clearDependencies() {
     282             :   after.clear();
     283      199562 : }
     284             : 
     285       66935 : void Action::checkRead() {
     286       66935 :   if(!line.empty()) {
     287           1 :     std::string msg="cannot understand the following words from the input line : ";
     288           2 :     for(unsigned i=0; i<line.size(); i++) {
     289           1 :       if(i>0) {
     290           0 :         msg = msg + ", ";
     291             :       }
     292           2 :       msg = msg + line[i];
     293             :     }
     294           1 :     error(msg);
     295             :   }
     296       66934 :   setupConstantValues(false);
     297       66934 : }
     298             : 
     299       95264 : void Action::setupConstantValues( const bool& have_atoms ) {
     300       95264 :   if( have_atoms ) {
     301             :     // This ensures that we switch off actions that only depend on constant when passed from the
     302             :     // MD code on the first step
     303       28330 :     ActionAtomistic* at = castToActionAtomistic();
     304       28330 :     ActionWithValue* av = castToActionWithValue();
     305       28330 :     if( at && av ) {
     306       16002 :       never_activate=av->getNumberOfComponents()>0;
     307       16049 :       for(unsigned i=0; i<av->getNumberOfComponents(); ++i) {
     308       16002 :         if( !av->copyOutput(i)->isConstant() ) {
     309       15955 :           never_activate=false;
     310       15955 :           break;
     311             :         }
     312             :       }
     313             :     }
     314             :   }
     315       95264 :   ActionWithArguments* aa = castToActionWithArguments();
     316      114486 :   if( aa && aa->getNumberOfArguments()>0 && getName()!="BIASVALUE" ) {
     317       18581 :     never_activate = aa->calculateConstantValues( have_atoms );
     318             :   }
     319       95264 : }
     320             : 
     321     5469614 : long long int Action::getStep()const {
     322     5469614 :   return plumed.getStep();
     323             : }
     324             : 
     325     3721732 : double Action::getTime()const {
     326     3721732 :   return timestep*getStep();
     327             : }
     328             : 
     329      219887 : double Action::getTimeStep()const {
     330      219887 :   return timestep;
     331             : }
     332             : 
     333         682 : double Action::getkBT() {
     334         682 :   double temp=-1.0;
     335        1364 :   if( keywords.exists("TEMP") ) {
     336        1336 :     parse("TEMP",temp);
     337             :   }
     338        1698 :   if(temp>=0.0 && keywords.style("TEMP","optional") ) {
     339         421 :     return getKBoltzmann()*temp;
     340             :   }
     341         261 :   ActionForInterface* kb=plumed.getActionSet().selectWithLabel<ActionForInterface*>("kBT");
     342             :   double kbt=0;
     343         261 :   if(kb) {
     344           3 :     kbt=(kb->copyOutput(0))->get();
     345             :   }
     346         377 :   if( temp>=0 && keywords.style("TEMP","compulsory") ) {
     347          58 :     double kB=getKBoltzmann();
     348          58 :     if( kbt>0 && std::abs(kbt-kB*temp)>1e-4) {
     349             :       std::string strt1, strt2;
     350           0 :       Tools::convert( temp, strt1 );
     351           0 :       Tools::convert( kbt/kB, strt2 );
     352           0 :       warning("using TEMP=" + strt1 + " while MD engine uses " + strt2 + "\n");
     353             :     }
     354          58 :     kbt = kB*temp;
     355          58 :     plumed_massert(kbt>0,"your MD engine does not pass the temperature to plumed, you must specify it using TEMP");
     356             :     return kbt;
     357             :   }
     358             :   return kbt;
     359             : }
     360             : 
     361           0 : void Action::exit(int c) {
     362           0 :   plumed.exit(c);
     363           0 : }
     364             : 
     365           0 : void Action::calculateNumericalDerivatives( ActionWithValue* a ) {
     366           0 :   plumed_merror("if you get here it means that you are trying to use numerical derivatives for a class that does not implement them");
     367             : }
     368             : 
     369     1025832 : void Action::prepare() {
     370     1025832 :   return;
     371             : }
     372             : 
     373          28 : [[noreturn]] void Action::error( const std::string & msg ) const {
     374          28 :   log.printf("ERROR in input to action %s with label %s : %s \n \n", name.c_str(), label.c_str(), msg.c_str() );
     375          84 :   plumed_merror("ERROR in input to action " + name + " with label " + label + " : " + msg );
     376             : }
     377             : 
     378        4304 : void Action::warning( const std::string & msg ) {
     379        4304 :   log.printf("WARNING for action %s with label %s : %s \n", name.c_str(), label.c_str(), msg.c_str() );
     380        4304 : }
     381             : 
     382           0 : void Action::calculateFromPDB( const PDB& pdb ) {
     383           0 :   activate();
     384           0 :   for(const auto & p : after) {
     385           0 :     ActionWithValue*av=castToActionWithValue();
     386           0 :     if(av) {
     387           0 :       av->clearInputForces();
     388           0 :       av->clearDerivatives();
     389             :     }
     390           0 :     p->readAtomsFromPDB( pdb );
     391           0 :     p->calculate();
     392             :   }
     393           0 :   readAtomsFromPDB( pdb );
     394           0 :   calculate();
     395           0 : }
     396             : 
     397       30198 : bool Action::getExchangeStep()const {
     398       30198 :   return plumed.getExchangeStep();
     399             : }
     400             : 
     401          41 : std::string Action::cite(const std::string&s) {
     402          41 :   return plumed.cite(s);
     403             : }
     404             : 
     405             : /// Check if action should be updated.
     406     2550402 : bool Action::checkUpdate()const {
     407     2550402 :   double t=getTime();
     408     2550402 :   if(t<update_until && (update_from==std::numeric_limits<double>::max() || t>=update_from)) {
     409             :     return true;
     410             :   } else {
     411         510 :     return false;
     412             :   }
     413             : }
     414             : 
     415        1340 : bool Action::getCPT() const {
     416        1340 :   return plumed.getCPT();
     417             : }
     418             : 
     419    15615301 : const Units& Action::getUnits() const {
     420    15615301 :   return plumed.getUnits();
     421             : }
     422             : 
     423        2197 : bool Action::usingNaturalUnits() const {
     424        2197 :   return plumed.usingNaturalUnits();
     425             : }
     426             : 
     427         714 : double Action::getKBoltzmann() const {
     428         714 :   if( usingNaturalUnits() ) {
     429             :     return 1.0;
     430             :   } else {
     431         714 :     return kBoltzmann/getUnits().getEnergy();
     432             :   }
     433             : }
     434             : 
     435          44 : std::string Action::writeInGraph() const {
     436          44 :   std::string nam=getName();
     437          44 :   std::size_t u=nam.find_last_of("_");
     438          44 :   std::string sub=nam.substr(u+1);
     439         118 :   if( sub=="SCALAR" || sub=="VECTOR" || sub=="GRID" ) {
     440           8 :     return nam.substr(0,u);
     441             :   }
     442             :   return nam;
     443             : }
     444             : 
     445             : }
     446             : 

Generated by: LCOV version 1.16