LCOV - code coverage report
Current view: top level - core - Action.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 195 236 82.6 %
Date: 2025-12-04 11:19:34 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 <iomanip>
      38             : #include <iostream>
      39             : #include <algorithm>
      40             : namespace PLMD {
      41             : 
      42             : Keywords ActionOptions::emptyKeys;
      43             : 
      44       49178 : ActionOptions::ActionOptions(PlumedMain&p,const std::vector<std::string>&l):
      45       49178 :   plumed(p),
      46       49178 :   line(l),
      47       49178 :   keys(emptyKeys) {
      48       49178 : }
      49             : 
      50       49176 : ActionOptions::ActionOptions(const ActionOptions&ao,const Keywords&mykeys):
      51       49176 :   plumed(ao.plumed),
      52       49176 :   line(ao.line),
      53       49176 :   keys(mykeys) {
      54       49176 : }
      55             : 
      56       70028 : void Action::registerKeywords( Keywords& keys ) {
      57       70028 :   plumed_assert( keys.size()==0 );
      58       70028 :   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" );
      59       70028 :   keys.reserve("optional","UPDATE_FROM","Only update this action from this time");
      60       70028 :   keys.reserve("optional","UPDATE_UNTIL","Only update this action until this time");
      61       70028 :   keys.reserve("optional","RESTART","allows per-action setting of restart (YES/NO/AUTO)");
      62       70028 : }
      63             : 
      64       49176 : Action::Action(const ActionOptions&ao):
      65       49176 :   actionName(ao.line[0]),
      66             :   //skipping the name with the +1
      67       49176 :   linemap(ao.line.begin()+1,ao.line.end()),
      68       49176 :   update_from(std::numeric_limits<double>::max()),
      69       49176 :   update_until(std::numeric_limits<double>::max()),
      70       49176 :   timestep(0),
      71       49176 :   active(false),
      72       49176 :   restart(ao.plumed.getRestart()),
      73       49176 :   doCheckPoint(ao.plumed.getCPT()),
      74       49176 :   never_activate(actionName=="CONSTANT"),
      75       49176 :   plumed(ao.plumed),
      76       49176 :   log(plumed.getLog()),
      77       49176 :   comm(plumed.comm),
      78       49176 :   multi_sim_comm(plumed.multi_sim_comm),
      79       98352 :   keywords(ao.keys) {
      80             :   // Retrieve the timestep and save it
      81       49176 :   resetStoredTimestep();
      82             : 
      83             :   //line.erase(line.begin());
      84             :   //making the line map
      85       49176 :   if( !keywords.exists("NO_ACTION_LOG") ) {
      86       34373 :     log.printf("Action %s\n",actionName.c_str());
      87       34373 :     if(ao.fullPath.length()>0) {
      88          41 :       log<<"  from library: "<<ao.fullPath<<"\n";
      89             :     }
      90             :   }
      91             : 
      92       49176 :   if(comm.Get_rank()==0) {
      93       35228 :     replica_index=multi_sim_comm.Get_rank();
      94             :   }
      95       49176 :   comm.Bcast(replica_index,0);
      96             : 
      97       49176 :   if ( keywords.exists("LABEL") ) {
      98       97884 :     parse("LABEL",actionLabel);
      99             :   }
     100       49176 :   if(actionLabel.length()==0) {
     101             :     std::string s;
     102        3278 :     Tools::convert(plumed.getActionSet().size()-plumed.getActionSet().select<ActionForInterface*>().size(),s);
     103        6556 :     actionLabel="@"+s;
     104       45898 :   } else if ( actionLabel.find(".")!=std::string::npos ) {
     105          14 :     warning("using full stop in an action label should be avaoided as . has a special meaning in PLUMED action labels");
     106             :   }
     107       49176 :   if( plumed.getActionSet().selectWithLabel<Action*>(actionLabel) ) {
     108           0 :     error("label " + actionLabel + " has been already used");
     109             :   }
     110       49176 :   if( !keywords.exists("NO_ACTION_LOG") ) {
     111       34373 :     log.printf("  with label %s\n",actionLabel.c_str());
     112             :   }
     113       49176 :   if ( keywords.exists("UPDATE_FROM") ) {
     114        4574 :     parse("UPDATE_FROM",update_from);
     115             :   }
     116       49176 :   if( !keywords.exists("NO_ACTION_LOG") && update_from!=std::numeric_limits<double>::max()) {
     117           5 :     log.printf("  only update from time %f\n",update_from);
     118             :   }
     119       49176 :   if ( keywords.exists("UPDATE_UNTIL") ) {
     120        4574 :     parse("UPDATE_UNTIL",update_until);
     121             :   }
     122       49176 :   if( !keywords.exists("NO_ACTION_LOG") && update_until!=std::numeric_limits<double>::max()) {
     123           5 :     log.printf("  only update until time %f\n",update_until);
     124             :   }
     125       49176 :   if ( keywords.exists("RESTART") ) {
     126        2250 :     std::string srestart="AUTO";
     127        2249 :     parse("RESTART",srestart);
     128        2249 :     if( plumed.parseOnlyMode() ) {
     129           0 :       restart=false;
     130        2249 :     } else if(srestart=="YES") {
     131         170 :       restart=true;
     132        2079 :     } else if(srestart=="NO") {
     133          22 :       restart=false;
     134        2057 :     } else if(srestart=="AUTO") {
     135             :       // do nothing, this is the default
     136             :     } else {
     137           2 :       error("RESTART should be either YES, NO, or AUTO");
     138             :     }
     139             :   }
     140       49175 : }
     141             : 
     142       96821 : void Action::resetStoredTimestep() {
     143       96821 :   ActionWithValue* ts = plumed.getActionSet().selectWithLabel<ActionWithValue*>("timestep");
     144       96821 :   if( ts ) {
     145       90416 :     timestep = (ts->copyOutput(0))->get();
     146             :   }
     147       96821 : }
     148             : 
     149       98350 : Action::~Action() {
     150       49175 :   if(files.size()!=0) {
     151           0 :     std::cerr<<"WARNING: some files open in action "+getLabel()+" where not properly closed. This could lead to data loss!!\n";
     152             :   }
     153       98350 : }
     154             : 
     155          82 : FILE* Action::fopen(const char *path, const char *mode) {
     156             :   bool write(false);
     157         164 :   for(const char*p=mode; *p; p++)
     158          82 :     if(*p=='w' || *p=='a' || *p=='+') {
     159             :       write=true;
     160             :     }
     161             :   FILE* fp;
     162          82 :   if(write && comm.Get_rank()!=0) {
     163           0 :     fp=plumed.fopen("/dev/null",mode);
     164             :   } else {
     165          82 :     fp=plumed.fopen(path,mode);
     166             :   }
     167          81 :   files.insert(fp);
     168          81 :   return fp;
     169             : }
     170             : 
     171          99 : int Action::fclose(FILE*fp) {
     172             :   files.erase(fp);
     173          99 :   return plumed.fclose(fp);
     174             : }
     175             : 
     176       59598 : void Action::fflush() {
     177       59598 :   for(const auto & p : files) {
     178           0 :     std::fflush(p);
     179             :   }
     180       59598 : }
     181             : 
     182           0 : std::string Action::getKeyword(const std::string& key) {
     183             :   // Check keyword has been registered
     184           0 :   plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered");
     185             : 
     186           0 :   std::string outkey=linemap.getKeyword(key);
     187           0 :   if(!outkey.empty()) {
     188             :     return outkey;
     189             :   }
     190           0 :   if( keywords.style(key,"compulsory") ) {
     191           0 :     if( keywords.getDefaultValue(key,outkey) ) {
     192           0 :       if( outkey.length()==0 ) {
     193           0 :         error("keyword " + key + " has weird default value");
     194             :       }
     195           0 :       return key + "=" +  outkey;
     196             :     } else {
     197           0 :       error("keyword " + key + " is compulsory for this action");
     198             :     }
     199             :   }
     200           0 :   return "";
     201             : }
     202             : 
     203       98175 : void Action::parseFlag(const std::string&key,bool & t) {
     204             :   // Check keyword has been registered
     205       98175 :   plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered");
     206             :   // Check keyword is a flag
     207      200650 :   plumed_massert( keywords.style(key,"deprecated") || keywords.style(key,"flag") || keywords.style(key,"hidden"), "keyword " + key + " is not a flag");
     208             : 
     209             :   // Read in the flag otherwise get the default value from the keywords object
     210       98175 :   t = linemap.readAndRemoveFlag(key);
     211       98175 :   if(!t) {
     212      171926 :     if( keywords.style(key,"nohtml") ) {
     213           0 :       t=false;
     214       85963 :     } else if ( !keywords.getLogicalDefault(key,t) ) {
     215           0 :       log.printf("ERROR in action %s with label %s : flag %s has no default",actionName.c_str(),actionLabel.c_str(),key.c_str() );
     216           0 :       plumed_error();
     217             :     }
     218             :   }
     219       98175 : }
     220             : 
     221     1250224 : void Action::addDependency(Action*action) {
     222             :   bool found=false;
     223    38394201 :   for(const auto & d : after ) {
     224    37396026 :     if( action==d ) {
     225             :       found=true;
     226             :       break;
     227             :     }
     228             :   }
     229     1250224 :   if( !found ) {
     230      998175 :     after.push_back(action);
     231             :   }
     232     1250224 : }
     233             : 
     234          70 : bool Action::checkForDependency( Action* action ) {
     235         135 :   for(const auto & d : after) {
     236          70 :     if( action==d ) {
     237             :       return true;
     238             :     }
     239          65 :     if( d->checkForDependency(action) ) {
     240             :       return true;
     241             :     }
     242             :   }
     243             :   return false;
     244             : }
     245             : 
     246     5385406 : void Action::activate() {
     247             : // This is set to true if actions are only need to be computed in setup (during checkRead)
     248     5385406 :   if( never_activate ) {
     249             :     return;
     250             :   }
     251             : // preparation step is called only the first time an Action is activated.
     252             : // since it could change its dependences (e.g. in an ActionAtomistic which is
     253             : // accessing to a virtual atom), this is done just before dependencies are
     254             : // activated
     255     5268371 :   if(!active) {
     256     2709746 :     this->unlockRequests();
     257     2709746 :     prepare();
     258     2709746 :     this->lockRequests();
     259             :   } else {
     260             :     return;
     261             :   }
     262     6730488 :   for(const auto & p : after) {
     263     4020742 :     p->activate();
     264             :   }
     265     2709746 :   active=true;
     266             : }
     267             : 
     268        2228 : void Action::setOption(const std::string &s) {
     269             : // This overloads the action and activate some options
     270        2228 :   actionOptions.insert(s);
     271        4370 :   for(const auto & p : after) {
     272        2142 :     p->setOption(s);
     273             :   }
     274        2228 : }
     275             : 
     276           0 : void Action::clearOptions() {
     277             : // This overloads the action and activate some options
     278             :   actionOptions.clear();
     279           0 : }
     280             : 
     281             : 
     282      198579 : void Action::clearDependencies() {
     283             :   after.clear();
     284      198579 : }
     285             : 
     286       65188 : void Action::checkRead() {
     287       65188 :   if (!linemap.empty()) {
     288           1 :     std::string msg="cannot understand the following words from the input line : ";
     289           2 :     msg += linemap.keyList(", ");
     290           1 :     error(msg);
     291             :   }
     292             : 
     293       65187 :   setupConstantValues(false);
     294       65187 : }
     295             : 
     296       93432 : void Action::setupConstantValues( const bool& have_atoms ) {
     297       93432 :   if( have_atoms ) {
     298             :     // This ensures that we switch off actions that only depend on constant when passed from the
     299             :     // MD code on the first step
     300       28245 :     ActionAtomistic* at = castToActionAtomistic();
     301       28245 :     ActionWithValue* av = castToActionWithValue();
     302       28245 :     if( at && av ) {
     303       15006 :       never_activate=av->getNumberOfComponents()>0;
     304       15037 :       for(unsigned i=0; i<av->getNumberOfComponents(); ++i) {
     305       15006 :         if( !av->copyOutput(i)->isConstant() ) {
     306       14975 :           never_activate=false;
     307       14975 :           break;
     308             :         }
     309             :       }
     310             :     }
     311             :   }
     312       93432 :   ActionWithArguments* aa = castToActionWithArguments();
     313      111010 :   if( aa && aa->getNumberOfArguments()>0 && getName()!="BIASVALUE" ) {
     314       16849 :     never_activate = aa->calculateConstantValues( have_atoms );
     315             :   }
     316       93432 : }
     317             : 
     318     5470497 : long long int Action::getStep()const {
     319     5470497 :   return plumed.getStep();
     320             : }
     321             : 
     322     3705407 : double Action::getTime()const {
     323     3705407 :   return timestep*getStep();
     324             : }
     325             : 
     326      219886 : double Action::getTimeStep()const {
     327      219886 :   return timestep;
     328             : }
     329             : 
     330         682 : double Action::getkBT() {
     331         682 :   double temp=-1.0;
     332         682 :   if( keywords.exists("TEMP") ) {
     333        1336 :     parse("TEMP",temp);
     334             :   }
     335        1698 :   if(temp>=0.0 && keywords.style("TEMP","optional") ) {
     336         421 :     return getKBoltzmann()*temp;
     337             :   }
     338         261 :   ActionForInterface* kb=plumed.getActionSet().selectWithLabel<ActionForInterface*>("kBT");
     339             :   double kbt=0;
     340         261 :   if(kb) {
     341           3 :     kbt=(kb->copyOutput(0))->get();
     342             :   }
     343         377 :   if( temp>=0 && keywords.style("TEMP","compulsory") ) {
     344          58 :     double kB=getKBoltzmann();
     345          58 :     if( kbt>0 && std::abs(kbt-kB*temp)>1e-4) {
     346             :       std::string strt1, strt2;
     347           0 :       Tools::convert( temp, strt1 );
     348           0 :       Tools::convert( kbt/kB, strt2 );
     349           0 :       warning("using TEMP=" + strt1 + " while MD engine uses " + strt2 + "\n");
     350             :     }
     351          58 :     kbt = kB*temp;
     352          58 :     plumed_massert(kbt>0,"your MD engine does not pass the temperature to plumed, you must specify it using TEMP");
     353             :     return kbt;
     354             :   }
     355             :   return kbt;
     356             : }
     357             : 
     358           0 : void Action::exit(int c) {
     359           0 :   plumed.exit(c);
     360           0 : }
     361             : 
     362           0 : void Action::calculateNumericalDerivatives( ActionWithValue* a ) {
     363           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");
     364             : }
     365             : 
     366     1118070 : void Action::prepare() {
     367     1118070 :   return;
     368             : }
     369             : 
     370          28 : [[noreturn]] void Action::error( const std::string & msg ) const {
     371          28 :   log.printf("ERROR in input to action %s with label %s : %s \n \n", actionName.c_str(), actionLabel.c_str(), msg.c_str() );
     372          84 :   plumed_merror("ERROR in input to action " + actionName + " with label " + actionLabel + " : " + msg );
     373             : }
     374             : 
     375        4240 : void Action::warning( const std::string & msg ) {
     376        4240 :   log.printf("WARNING for action %s with label %s : %s \n", actionName.c_str(), actionLabel.c_str(), msg.c_str() );
     377        4240 : }
     378             : 
     379           0 : void Action::calculateFromPDB( const PDB& pdb ) {
     380           0 :   activate();
     381           0 :   for(const auto & p : after) {
     382           0 :     ActionWithValue*av=castToActionWithValue();
     383           0 :     if(av) {
     384           0 :       av->clearInputForces();
     385           0 :       av->clearDerivatives();
     386             :     }
     387           0 :     p->readAtomsFromPDB( pdb );
     388           0 :     p->calculate();
     389             :   }
     390           0 :   readAtomsFromPDB( pdb );
     391           0 :   calculate();
     392           0 : }
     393             : 
     394       30480 : bool Action::getExchangeStep()const {
     395       30480 :   return plumed.getExchangeStep();
     396             : }
     397             : 
     398          41 : std::string Action::cite(const std::string&s) {
     399          41 :   return plumed.cite(s);
     400             : }
     401             : 
     402             : /// Check if action should be updated.
     403     2568758 : bool Action::checkUpdate()const {
     404     2568758 :   double t=getTime();
     405     2568758 :   if(t<update_until && (update_from==std::numeric_limits<double>::max() || t>=update_from)) {
     406             :     return true;
     407             :   } else {
     408         510 :     return false;
     409             :   }
     410             : }
     411             : 
     412        1340 : bool Action::getCPT() const {
     413        1340 :   return plumed.getCPT();
     414             : }
     415             : 
     416    16247442 : const Units& Action::getUnits() const {
     417    16247442 :   return plumed.getUnits();
     418             : }
     419             : 
     420        2199 : bool Action::usingNaturalUnits() const {
     421        2199 :   return plumed.usingNaturalUnits();
     422             : }
     423             : 
     424         714 : double Action::getKBoltzmann() const {
     425         714 :   if( usingNaturalUnits() ) {
     426             :     return 1.0;
     427             :   } else {
     428         714 :     return kBoltzmann/getUnits().getEnergy();
     429             :   }
     430             : }
     431             : 
     432          56 : std::string Action::writeInGraph() const {
     433          56 :   std::string nam=getName();
     434          56 :   std::size_t u=nam.find_last_of("_");
     435          56 :   std::string sub=nam.substr(u+1);
     436         154 :   if( sub=="SCALAR" || sub=="VECTOR" || sub=="GRID" ) {
     437           8 :     return nam.substr(0,u);
     438             :   }
     439             :   return nam;
     440             : }
     441             : 
     442             : }
     443             : 

Generated by: LCOV version 1.16