LCOV - code coverage report
Current view: top level - core - Action.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 92 106 86.8 %
Date: 2026-11-05 10:19:04 Functions: 36 39 92.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             : #ifndef __PLUMED_core_Action_h
      23             : #define __PLUMED_core_Action_h
      24             : #include <iomanip>
      25             : #include <vector>
      26             : #include <string>
      27             : #include <set>
      28             : #include "tools/Keywords.h"
      29             : #include "tools/Tools.h"
      30             : #include "tools/Units.h"
      31             : #include "tools/Log.h"
      32             : #include "tools/TokenizedLine.h"
      33             : 
      34             : namespace PLMD {
      35             : 
      36             : class PDB;
      37             : class PlumedMain;
      38             : class Communicator;
      39             : class ActionWithValue;
      40             : class ActionWithArguments;
      41             : class ActionAtomistic;
      42             : class ActionWithVirtualAtom;
      43             : class PbcAction;
      44             : class ActionToGetData;
      45             : class ActionToPutData;
      46             : class DomainDecomposition;
      47             : class ActionForInterface;
      48             : class ActionShortcut;
      49             : 
      50             : /// This class is used to bring the relevant information to the Action constructor.
      51             : /// Only Action and ActionRegister class can access to its content, which is
      52             : /// kept private to other classes, and may change in the future.
      53      132068 : class ActionOptions {
      54             :   friend class Action;
      55             :   friend class ActionRegister;
      56             : /// Reference to main PlumedMain object
      57             :   PlumedMain& plumed;
      58             : /// Input line which sets up the action
      59             :   std::vector<std::string> line;
      60             : /// The documentation for this action
      61             :   const Keywords& keys;
      62             :   static Keywords emptyKeys;
      63             :   std::string fullPath;
      64             : public:
      65             : /// Constructor
      66             :   ActionOptions(PlumedMain&p,const std::vector<std::string>&);
      67             :   ActionOptions(const ActionOptions&,const Keywords& keys);
      68             :   void setFullPath(const std::string & newFullPath) {
      69             :     fullPath=newFullPath;
      70       66033 :   }
      71             : };
      72             : 
      73             : /// Base class for all the input Actions.
      74             : /// The input Actions are more or less corresponding to the directives
      75             : /// in the plumed.dat file and are applied in order at each time-step.
      76             : class Action {
      77             :   friend class ActionShortcut;
      78             :   using KeyMap = TokenizedLine;
      79             : /// Name of the directive in the plumed.dat file.
      80             :   const std::string actionName;
      81             : 
      82             : /// Label of the Action, as set with LABEL= in the plumed.dat file.
      83             :   std::string actionLabel;
      84             : 
      85             : /// Directive line.
      86             : /// This line is progressively erased during Action construction
      87             : /// so as to check if all the present keywords are correct.
      88             :   KeyMap linemap;
      89             : /// Update only after this time.
      90             :   double update_from;
      91             : 
      92             : /// Update only until this time.
      93             :   double update_until;
      94             : 
      95             : /// Save the timestep here
      96             :   double timestep;
      97             : 
      98             : protected:
      99             : /// Get the units that we are operating in
     100             :   const Units& getUnits() const;
     101             : /// Are we using natural units
     102             :   bool usingNaturalUnits()const;
     103             : /// Get the value of Boltzmann's constant
     104             :   double getKBoltzmann()const;
     105             : public:
     106             : 
     107             : /// Check if action should be updated.
     108             :   bool checkUpdate()const;
     109             : 
     110             : public:
     111             :   typedef std::vector<Action*> Dependencies;
     112             : 
     113             : private:
     114             : /// Actions on which this Action depends.
     115             :   Dependencies after;
     116             : 
     117             : /// Switch to activate Action on this step.
     118             :   bool active;
     119             : 
     120             : /// Option that you might have enabled
     121             :   std::set<std::string> actionOptions;
     122             : 
     123             :   bool restart;
     124             : 
     125             :   bool doCheckPoint;
     126             : 
     127             :   bool never_activate;
     128             : 
     129             : /// The set of default arguments that we are using
     130             :   std::string defaults;
     131             : public:
     132             : 
     133             : /// Reference to main plumed object
     134             :   PlumedMain& plumed;
     135             : 
     136             : /// Reference to the log stream
     137             :   Log& log;
     138             : 
     139             : /// Specify that this Action depends on another one
     140             :   void addDependency(Action*);
     141             : 
     142             : /// Check that this action does not depend on the action in the argument
     143             :   bool checkForDependency(Action*);
     144             : 
     145             : /// Clear the dependence list for this Action
     146             :   void clearDependencies();
     147             : 
     148             : /// Get the value of kBT by either reading the TEMP keyword
     149             : /// and multiplying the temperature by Boltzmann's constant
     150             : /// or get it fro the MD code
     151             :   double getkBT();
     152             : 
     153             : /// Return the present timestep
     154             :   long long int getStep()const;
     155             : 
     156             : /// Return the present time
     157             :   double getTime()const;
     158             : 
     159             : /// Return the timestep
     160             :   double getTimeStep()const;
     161             : 
     162             : /// Return true if we are doing a restart
     163             :   bool getRestart()const;
     164             : 
     165             : /// Return true if we are doing at a checkpoint step
     166             :   bool getCPT()const;
     167             : 
     168             : /// Just read one of the keywords and return the whole thing as a string
     169             :   std::string getKeyword(const std::string& key);
     170             : 
     171             : /// Parse one keyword as generic type
     172             :   template<class T>
     173             :   void parse(const std::string&key,T&t);
     174             : 
     175             : /// Parse one numbered keyword as generic type
     176             :   template<class T>
     177             :   bool parseNumbered(const std::string&key, const int no, T&t);
     178             : 
     179             : /// Parse one keyword as std::vector
     180             :   template<class T>
     181             :   void parseVector(const std::string&key,std::vector<T>&t);
     182             : 
     183             : /// Parse a vector with a number
     184             :   template<class T>
     185             :   bool parseNumberedVector(const std::string& key, const int no, std::vector<T>&t);
     186             : 
     187             : /// Parse one keyword as boolean flag
     188             :   void parseFlag(const std::string&key,bool&t);
     189             : 
     190             : /// Crash calculation and print documentation
     191             :   [[noreturn]] void error( const std::string & msg ) const;
     192             : 
     193             : /// Issue a warning
     194             :   void warning( const std::string & msg );
     195             : 
     196             : /// Exit with error code c
     197             :   void exit(int c=0);
     198             : 
     199             : ///
     200             :   std::set<FILE*> files;
     201             : 
     202             : public:
     203             : /// Standard constructor from ActionOptions
     204             :   explicit Action(const ActionOptions&);
     205             : /// Destructor
     206             :   virtual ~Action();
     207             : private:
     208             : /// Copy constructor is deleted
     209             :   Action(const Action&a) = delete;
     210             : /// Assignment operator is deleted
     211             :   Action& operator=(const Action&a) = delete;
     212             :   int replica_index;
     213             : public:
     214             : /// Check if Action was properly read.
     215             : /// This checks if Action::line is empty. It must be called after
     216             : /// a final Action has been initialized
     217             :   void checkRead();
     218             : 
     219             : /// This calculates any values that are constant and ensures
     220             : /// that we don't calculate these actions on every timestep
     221             :   void setupConstantValues( const bool& have_atoms );
     222             : 
     223             : /// Communicator of this replica: all the MPI processes running this PLUMED
     224             : /// instance (set by the MD code with setMPIComm). It is valid on every process.
     225             :   Communicator& comm;
     226             : 
     227             : /// Communicator between replicas, in multiple-replica simulations.
     228             : /// It holds one process per replica, namely process 0 of comm (set with
     229             : /// GREX setMPIIntercomm or setMPImultiSimComm).
     230             : /// It is valid only on process 0 of comm. On the other processes it is
     231             : /// MPI_COMM_SELF, so Get_size() returns 1 and Get_rank() returns 0 whatever
     232             : /// the number of replicas, and communication over it reaches no other replica.
     233             : /// Code that needs the number of replicas or the replica index on every
     234             : /// process must read them on process 0 of comm and broadcast them over comm:
     235             : /// \code
     236             : /// unsigned nrep=0, irep=0;
     237             : /// if(comm.Get_rank()==0) {
     238             : ///   nrep=multi_sim_comm.Get_size();
     239             : ///   irep=multi_sim_comm.Get_rank();
     240             : /// }
     241             : /// comm.Bcast(nrep,0);
     242             : /// comm.Bcast(irep,0);
     243             : /// \endcode
     244             : /// The same applies to communication over multi_sim_comm: do it on process 0
     245             : /// of comm, then broadcast the result over comm.
     246             : /// For how MD codes set up these communicators, see \ref mpireplicas.
     247             :   Communicator& multi_sim_comm;
     248             : 
     249             : /// Number of replicas in a multi-replica simulation (1 otherwise), and the index
     250             : /// of this replica. Prefer these to multi_sim_comm.Get_size() and Get_rank(), which
     251             : /// are only correct on the rank that received the inter-replica communicator: with
     252             : /// several ranks per replica, the others see a single replica. These are computed
     253             : /// once at initialization, so they are correct on every rank and need no
     254             : /// communication, which makes them safe to call anywhere, including calculate().
     255             : /// multi_sim_comm is still the communicator to use for exchanging data, and only on
     256             : /// the rank that holds it.
     257             :   int getNumberOfReplicas() const;
     258             :   int getReplicaIndex() const;
     259             : 
     260             :   const Keywords& keywords;
     261             : /// Prepare an Action for calculation
     262             : /// This can be used by Action if they need some special preparation
     263             : /// before calculation. Typical case is for collective variables
     264             : /// which would like to change their list of requested atoms.
     265             : /// By default (if not overridden) does nothing.
     266             :   virtual void prepare();
     267             : 
     268             : /// Register all the relevant keywords for the action
     269             :   static void registerKeywords( Keywords& keys );
     270             : 
     271     2152834 :   virtual void lockRequests() {}
     272     2152834 :   virtual void unlockRequests() {}
     273             : 
     274             : /// Calculate an Action.
     275             : /// This method is called one or more times per step.
     276             : /// The set of all Actions is calculated in forward order.
     277             :   virtual void calculate()=0;
     278             : 
     279             : /// Apply an Action.
     280             : /// This method is called one time per step.
     281             : /// The set of all Actions is applied in backward order.
     282             :   virtual void apply()=0;
     283             : 
     284             : /// Before Update.
     285             : /// This is a special method that is called just
     286             : /// before the update() method. It can be used by
     287             : /// actions that want to do something irrespectively
     288             : /// of the fact that update() is active or not.
     289             : /// In other words, this is *always* called, even when action
     290             : /// is not active.
     291     5397106 :   virtual void beforeUpdate() {}
     292             : 
     293             : /// Update.
     294             : /// This method is called one time per step.
     295             : /// The set of all Actions is updated in forward order.
     296     2144965 :   virtual void update() {}
     297             : 
     298             : /// RunFinalJobs
     299             : /// This method is called once at the very end of the calculation.
     300             : /// The set of all Actions in run for the final time in forward order.
     301       50283 :   virtual void runFinalJobs() {}
     302             : 
     303             : /// Tell to the Action to flush open files
     304             :   void fflush();
     305             : 
     306             : /// Returns the label
     307             :   const std::string & getLabel()const;
     308             : 
     309             : /// Returns the name
     310             :   const std::string & getName()const;
     311             : 
     312             : /// Set action to active
     313             :   virtual void activate();
     314             : 
     315             : ///
     316             :   virtual void setOption(const std::string &s);
     317             : 
     318             :   virtual void clearOptions();
     319             : 
     320             : /// Set action to inactive
     321             :   virtual void deactivate();
     322             : 
     323             : /// Check if action is active
     324             :   bool isActive()const;
     325             : 
     326             : /// Check if an option is on
     327             :   bool isOptionOn(const std::string &s)const;
     328             : 
     329             : /// Return dependencies
     330             :   const Dependencies & getDependencies()const {
     331             :     return after;
     332             :   }
     333             : 
     334             : /// Check if numerical derivatives should be performed
     335      333456 :   virtual bool checkNumericalDerivatives()const {
     336      333456 :     return false;
     337             :   }
     338             : 
     339             : /// Check if the action needs gradient
     340     3637084 :   virtual bool checkNeedsGradients()const {
     341     3637084 :     return false;
     342             :   }
     343             : 
     344             : /// Perform calculation using numerical derivatives
     345             : /// N.B. only pass an ActionWithValue to this routine if you know exactly what you
     346             : /// are doing.
     347             :   virtual void calculateNumericalDerivatives( ActionWithValue* a=NULL );
     348             : 
     349             : /// Opens a file.
     350             : /// This is similar to plain fopen, but with some extra functionality.
     351             : /// * When opened for writing, processors other than the one with rank 0 just open /dev/null
     352             : /// * PlumedMain::fopen is used, so that other tricks may appear (see \ref PlumedMain::fopen)
     353             :   FILE *fopen(const char *path, const char *mode);
     354             : /// Closes a file opened with Action::fclose().
     355             :   int   fclose(FILE*fp);
     356             : 
     357             : /// Calculate the action given a pdb file as input.  This is used to initialize
     358             : /// things like distance from a point in CV map space given a pdb as an input file
     359             :   void calculateFromPDB( const PDB&  );
     360             : /// This is overwritten in ActionAtomistic so that we can read
     361             : /// the atoms from the pdb input file rather than taking them from the
     362             : /// MD code
     363           0 :   virtual void readAtomsFromPDB( const PDB&  ) {}
     364             : /// Check if we are on an exchange step
     365             :   bool getExchangeStep()const;
     366             : 
     367             : /// Cite a paper see PlumedMain::cite
     368             :   std::string cite(const std::string&s);
     369             : 
     370             : /// Get the defaults
     371             :   std::string getDefaultString() const ;
     372             : 
     373             : /// Set the timestep that is stored in the action to the correct value
     374             :   void resetStoredTimestep();
     375             : 
     376             : /// Get the info on what to calculate
     377             :   virtual std::string writeInGraph() const ;
     378             : /// Specialized casts, to make PlumedMain run faster
     379      346540 :   virtual ActionWithValue* castToActionWithValue() noexcept {
     380      346540 :     return nullptr;
     381             :   }
     382       92874 :   virtual ActionWithArguments* castToActionWithArguments() noexcept {
     383       92874 :     return nullptr;
     384             :   }
     385     3108135 :   virtual ActionAtomistic* castToActionAtomistic() noexcept {
     386     3108135 :     return nullptr;
     387             :   }
     388     3677991 :   virtual ActionWithVirtualAtom* castToActionWithVirtualAtom() noexcept {
     389     3677991 :     return nullptr;
     390             :   }
     391           0 :   virtual PbcAction* castToPbcAction() noexcept {
     392           0 :     return nullptr;
     393             :   }
     394       27281 :   virtual ActionToPutData* castToActionToPutData() noexcept {
     395       27281 :     return nullptr;
     396             :   }
     397           0 :   virtual ActionToGetData* castToActionToGetData() noexcept {
     398           0 :     return nullptr;
     399             :   }
     400       11392 :   virtual DomainDecomposition* castToDomainDecomposition() noexcept {
     401       11392 :     return nullptr;
     402             :   }
     403         666 :   virtual ActionForInterface* castToActionForInterface() noexcept {
     404         666 :     return nullptr;
     405             :   }
     406          98 :   virtual ActionShortcut* castToActionShortcut() noexcept {
     407          98 :     return nullptr;
     408             :   }
     409             : };
     410             : 
     411             : /////////////////////
     412             : // FAST INLINE METHODS
     413             : 
     414             : inline
     415             : const std::string & Action::getLabel()const {
     416    48435180 :   return actionLabel;
     417             : }
     418             : 
     419             : inline
     420             : const std::string & Action::getName()const {
     421     1135555 :   return actionName;
     422             : }
     423             : 
     424             : template<class T>
     425      193202 : void Action::parse(const std::string&key,T&t) {
     426             :   // Check keyword has been registered
     427      193202 :   plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered");
     428             : 
     429             :   // Now try to read the keyword
     430      193202 :   auto [present, found] = linemap.readAndRemove(key,t,replica_index);
     431             : 
     432      193202 :   if(present && !found) {
     433           6 :     error("keyword " + key +" could not be read correctly");
     434             :   }
     435             : 
     436             :   // If it isn't read and it is compulsory see if a default value was specified
     437      330847 :   if ( !found && (keywords.style(key,"compulsory") || keywords.style(key,"hidden")) ) {
     438             :     std::string def;
     439       32154 :     if( keywords.getDefaultValue(key,def) ) {
     440       24190 :       if( def.length()==0 || !Tools::convertNoexcept(def,t) ) {
     441           0 :         plumed_error() <<"ERROR in action "<<actionName<<" with label "<<actionLabel<<" : keyword "<<key<<" has weird default value";
     442       24190 :       } else if( def.find(" ")!=std::string::npos ) {
     443          48 :         def = "{" + def + "}";
     444             :       }
     445       72570 :       defaults += " " + key + "=" + def;
     446       15928 :     } else if( keywords.style(key,"compulsory") ) {
     447           0 :       error("keyword " + key + " is compulsory for this action");
     448             :     }
     449             :   }
     450      193199 : }
     451             : 
     452             : template<class T>
     453       69639 : bool Action::parseNumbered(const std::string&key, const int no, T&t) {
     454             :   // Check keyword has been registered
     455       69639 :   plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered");
     456       69639 :   if( !keywords.numbered(key) ) {
     457           0 :     error("numbered keywords are not allowed for " + key );
     458             :   }
     459             : 
     460             :   // Now try to read the keyword
     461             :   std::string num;
     462       69639 :   Tools::convert(no,num);
     463       69639 :   auto [present, found] = linemap.readAndRemove(key+num,t,replica_index);
     464       69639 :   return found;
     465             : }
     466             : 
     467             : template<class T>
     468      109172 : void Action::parseVector(const std::string&key,std::vector<T>&t) {
     469             :   // Check keyword has been registered
     470      109172 :   plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered");
     471      109172 :   unsigned size=t.size();
     472             :   bool skipcheck=false;
     473      109172 :   if(size==0) {
     474             :     skipcheck=true;
     475             :   }
     476             :   // Now try to read the keyword
     477      109172 :   auto [present, found] = linemap.readAndRemoveVector(key,t,replica_index);
     478      109172 :   if(present && !found) {
     479           0 :     error("keyword " + key +" could not be read correctly");
     480             :   }
     481             : 
     482             :   // Check vectors size is correct (not if this is atoms or ARG)
     483      218344 :   if( !keywords.style(key,"atoms") && found ) {
     484       69076 :     if( !skipcheck && t.size()!=size ) {
     485           6 :       error("vector read in for keyword " + key + " has the wrong size");
     486             :     }
     487             :   }
     488             : 
     489             :   // If it isn't read and it is compulsory see if a default value was specified
     490      151255 :   if ( !found && (keywords.style(key,"compulsory") || keywords.style(key,"hidden")) ) {
     491             :     T val;
     492             :     std::string def;
     493        6165 :     if( keywords.getDefaultValue(key,def) ) {
     494        6014 :       if( def.length()==0 || !Tools::convertNoexcept(def,val) ) {
     495           0 :         plumed_error() <<"ERROR in action "<<actionName<<" with label "<<actionLabel<<" : keyword "<<key<<" has weird default value";
     496             :       } else {
     497        6014 :         if(t.size()>0) {
     498        9788 :           for(unsigned i=0; i<t.size(); ++i) {
     499        4213 :             t[i]=val;
     500             :           }
     501        6018 :           defaults += " " + key + "=" + def;
     502        6779 :           for(unsigned i=1; i<t.size(); ++i) {
     503        7540 :             defaults += "," + def;
     504             :           }
     505             :         } else {
     506        3005 :           t.push_back(val);
     507        9015 :           defaults += " " + key + "=" + def;
     508             :         }
     509             :       }
     510         302 :     } else if( keywords.style(key,"compulsory") ) {
     511           0 :       error("keyword " + key + " is compulsory for this action");
     512             :     }
     513      103004 :   } else if ( !found ) {
     514       17885 :     t.resize(0);
     515             :   }
     516      109169 : }
     517             : 
     518             : template<class T>
     519      437083 : bool Action::parseNumberedVector(const std::string&key,
     520             :                                  const int no,
     521             :                                  std::vector<T>&t) {
     522      437083 :   plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered");
     523      437083 :   if( !keywords.numbered(key) ) {
     524           0 :     error("numbered keywords are not allowed for " + key );
     525             :   }
     526             : 
     527      437083 :   unsigned size=t.size();
     528             :   bool skipcheck=size==0;
     529             :   std::string num;
     530      437083 :   Tools::convert(no,num);
     531      437083 :   auto [present, found] = linemap.readAndRemoveVector(key+num,t,replica_index);
     532      437083 :   if(present && !found) {
     533           0 :     error("keyword " + key +" could not be read correctly");
     534             :   }
     535             : 
     536      874166 :   if(  keywords.style(key,"compulsory") ) {
     537         138 :     if (!skipcheck && found && t.size()!=size ) {
     538           0 :       error("vector read in for keyword " + key + num + " has the wrong size");
     539             :     }
     540      436945 :   } else if ( !found ) {
     541        2133 :     t.resize(0);
     542             :   }
     543      437083 :   return found;
     544             : }
     545             : 
     546             : inline
     547     5778282 : void Action::deactivate() {
     548             :   actionOptions.clear();
     549     5778282 :   active=false;
     550     5778282 : }
     551             : 
     552             : inline
     553             : bool Action::isActive()const {
     554    25920271 :   return active;
     555             : }
     556             : 
     557             : inline
     558     2183188 : bool Action::isOptionOn(const std::string &s)const {
     559     2183188 :   return actionOptions.count(s);
     560             : }
     561             : 
     562             : inline
     563             : bool Action::getRestart()const {
     564        6320 :   return restart;
     565             : }
     566             : 
     567             : inline
     568             : std::string Action::getDefaultString() const {
     569          32 :   return defaults;
     570             : }
     571             : 
     572             : }
     573             : #endif
     574             : 

Generated by: LCOV version 1.16