1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2    Copyright (c) 2011-2021 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 <vector>
25 #include <string>
26 #include <set>
27 #include "tools/Keywords.h"
28 #include "tools/Tools.h"
29 #include "tools/Log.h"
30 
31 namespace PLMD {
32 
33 class PDB;
34 class PlumedMain;
35 class Communicator;
36 class ActionWithValue;
37 
38 /// This class is used to bring the relevant information to the Action constructor.
39 /// Only Action and ActionRegister class can access to its content, which is
40 /// kept private to other classes, and may change in the future.
41 class ActionOptions {
42   friend class Action;
43   friend class ActionRegister;
44 /// Reference to main PlumedMain object
45   PlumedMain& plumed;
46 /// Input line which sets up the action
47   std::vector<std::string> line;
48 /// The documentation for this action
49   const Keywords& keys;
50   static Keywords emptyKeys;
51 public:
52 /// Constructor
53   ActionOptions(PlumedMain&p,const std::vector<std::string>&);
54   ActionOptions(const ActionOptions&,const Keywords& keys);
55 };
56 
57 /// Base class for all the input Actions.
58 /// The input Actions are more or less corresponding to the directives
59 /// in the plumed.dat file and are applied in order at each time-step.
60 class Action {
61   friend class ActionShortcut;
62 
63 /// Name of the directive in the plumed.dat file.
64   const std::string name;
65 
66 /// Label of the Action, as set with LABEL= in the plumed.dat file.
67   std::string label;
68 
69 /// Directive line.
70 /// This line is progressively erased during Action construction
71 /// so as to check if all the present keywords are correct.
72   std::vector<std::string> line;
73 
74 /// Update only after this time.
75   double update_from;
76 
77 /// Update only until this time.
78   double update_until;
79 
80 public:
81 
82 /// Check if action should be updated.
83   bool checkUpdate()const;
84 
85 public:
86   typedef std::vector<Action*> Dependencies;
87 
88 private:
89 /// Actions on which this Action depends.
90   Dependencies after;
91 
92 /// Switch to activate Action on this step.
93   bool active;
94 
95 /// Option that you might have enabled
96   std::set<std::string> options;
97 
98   bool restart;
99 
100   bool doCheckPoint;
101 
102 public:
103 
104 /// Reference to main plumed object
105   PlumedMain& plumed;
106 
107 /// Reference to the log stream
108   Log& log;
109 
110 /// Specify that this Action depends on another one
111   void addDependency(Action*);
112 
113 /// Clear the dependence list for this Action
114   void clearDependencies();
115 
116 /// Return the present timestep
117   long int getStep()const;
118 
119 /// Return the present time
120   double getTime()const;
121 
122 /// Return the timestep
123   double getTimeStep()const;
124 
125 /// Return true if we are doing a restart
126   bool getRestart()const;
127 
128 /// Return true if we are doing at a checkpoint step
129   bool getCPT()const;
130 
131 /// Just read one of the keywords and return the whole thing as a string
132   std::string getKeyword(const std::string& key);
133 
134 /// Parse one keyword as generic type
135   template<class T>
136   void parse(const std::string&key,T&t);
137 
138 /// Parse one numbered keyword as generic type
139   template<class T>
140   bool parseNumbered(const std::string&key, const int no, T&t);
141 
142 /// Parse one keyword as std::vector
143   template<class T>
144   void parseVector(const std::string&key,std::vector<T>&t);
145 
146 /// Parse a vector with a number
147   template<class T>
148   bool parseNumberedVector(const std::string& key, const int no, std::vector<T>&t);
149 
150 /// Parse one keyword as boolean flag
151   void parseFlag(const std::string&key,bool&t);
152 
153 /// Crash calculation and print documentation
154   void error( const std::string & msg ) const;
155 
156 /// Issue a warning
157   void warning( const std::string & msg );
158 
159 /// Exit with error code c
160   void exit(int c=0);
161 
162 ///
163   std::set<FILE*> files;
164 
165 public:
166 /// Standard constructor from ActionOptions
167   explicit Action(const ActionOptions&);
168 /// Destructor
169   virtual ~Action();
170 private:
171 /// Copy constructor is deleted
172   Action(const Action&a) = delete;
173 /// Assignment operator is deleted
174   Action& operator=(const Action&a) = delete;
175   int replica_index;
176 public:
177 /// Check if Action was properly read.
178 /// This checks if Action::line is empty. It must be called after
179 /// a final Action has been initialized
180   void checkRead();
181 
182   Communicator& comm;
183   Communicator& multi_sim_comm;
184 
185   const Keywords& keywords;
186 /// Prepare an Action for calculation
187 /// This can be used by Action if they need some special preparation
188 /// before calculation. Typical case is for collective variables
189 /// which would like to change their list of requested atoms.
190 /// By default (if not overridden) does nothing.
191   virtual void prepare();
192 
193 /// Register all the relevant keywords for the action
194   static void registerKeywords( Keywords& keys );
195 
lockRequests()196   virtual void lockRequests() {}
unlockRequests()197   virtual void unlockRequests() {}
198 
199 /// Calculate an Action.
200 /// This method is called one or more times per step.
201 /// The set of all Actions is calculated in forward order.
202   virtual void calculate()=0;
203 
204 /// Apply an Action.
205 /// This method is called one time per step.
206 /// The set of all Actions is applied in backward order.
207   virtual void apply()=0;
208 
209 /// Before Update.
210 /// This is a special method that is called just
211 /// before the update() method. It can be used by
212 /// actions that want to do something irrespectively
213 /// of the fact that update() is active or not.
214 /// In other words, this is *always* called, even when action
215 /// is not active.
beforeUpdate()216   virtual void beforeUpdate() {}
217 
218 /// Update.
219 /// This method is called one time per step.
220 /// The set of all Actions is updated in forward order.
update()221   virtual void update() {}
222 
223 /// RunFinalJobs
224 /// This method is called once at the very end of the calculation.
225 /// The set of all Actions in run for the final time in forward order.
runFinalJobs()226   virtual void runFinalJobs() {}
227 
228 /// Tell to the Action to flush open files
229   void fflush();
230 
231   virtual std::string getDocumentation()const;
232 
233 /// Returns the label
234   const std::string & getLabel()const;
235 
236 /// Returns the name
237   const std::string & getName()const;
238 
239 /// Set action to active
240   virtual void activate();
241 
242 ///
243   virtual void setOption(const std::string &s);
244 
245   virtual void clearOptions();
246 
247 /// Set action to inactive
248   virtual void deactivate();
249 
250 /// Check if action is active
251   bool isActive()const;
252 
253 /// Check if an option is on
254   bool isOptionOn(const std::string &s)const;
255 
256 /// Return dependencies
getDependencies()257   const Dependencies & getDependencies()const {return after;}
258 
259 /// Check if numerical derivatives should be performed
checkNumericalDerivatives()260   virtual bool checkNumericalDerivatives()const {return false;}
261 
262 /// Check if the action needs gradient
checkNeedsGradients()263   virtual bool checkNeedsGradients()const {return false;}
264 
265 /// Perform calculation using numerical derivatives
266 /// N.B. only pass an ActionWithValue to this routine if you know exactly what you
267 /// are doing.
268   virtual void calculateNumericalDerivatives( ActionWithValue* a=NULL );
269 
270 /// Opens a file.
271 /// This is similar to plain fopen, but with some extra functionality.
272 /// * When opened for writing, processors other than the one with rank 0 just open /dev/null
273 /// * PlumedMain::fopen is used, so that other tricks may appear (see \ref PlumedMain::fopen)
274   FILE *fopen(const char *path, const char *mode);
275 /// Closes a file opened with Action::fclose().
276   int   fclose(FILE*fp);
277 
278 /// Calculate the action given a pdb file as input.  This is used to initialize
279 /// things like distance from a point in CV map space given a pdb as an input file
280   void calculateFromPDB( const PDB&  );
281 /// This is overwritten in ActionAtomistic so that we can read
282 /// the atoms from the pdb input file rather than taking them from the
283 /// MD code
readAtomsFromPDB(const PDB &)284   virtual void readAtomsFromPDB( const PDB&  ) {}
285 /// Check if we are on an exchange step
286   bool getExchangeStep()const;
287 
288 /// Cite a paper see PlumedMain::cite
289   std::string cite(const std::string&s);
290 };
291 
292 /////////////////////
293 // FAST INLINE METHODS
294 
295 inline
getLabel()296 const std::string & Action::getLabel()const {
297   return label;
298 }
299 
300 inline
getName()301 const std::string & Action::getName()const {
302   return name;
303 }
304 
305 template<class T>
parse(const std::string & key,T & t)306 void Action::parse(const std::string&key,T&t) {
307 //  if(!Tools::parse(line,key,t)){
308 //    log.printf("ERROR parsing keyword %s\n",key.c_str());
309 //    log.printf("%s\n",getDocumentation().c_str());
310 //    this->exit(1);
311 //  }
312   // Check keyword has been registered
313   plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered");
314 
315   // Now try to read the keyword
316   std::string def;
317   bool present=Tools::findKeyword(line,key);
318   bool found=Tools::parse(line,key,t,replica_index);
319   if(present && !found) error("keyword " + key +" could not be read correctly");
320 
321   // If it isn't read and it is compulsory see if a default value was specified
322   if ( !found && (keywords.style(key,"compulsory") || keywords.style(key,"hidden")) ) {
323     if( keywords.getDefaultValue(key,def) ) {
324       if( def.length()==0 || !Tools::convert(def,t) ) {
325         log.printf("ERROR in action %s with label %s : keyword %s has weird default value",name.c_str(),label.c_str(),key.c_str() );
326         this->exit(1);
327       }
328     } else if( keywords.style(key,"compulsory") ) {
329       error("keyword " + key + " is compulsory for this action");
330     }
331   }
332 }
333 
334 template<class T>
parseNumbered(const std::string & key,const int no,T & t)335 bool Action::parseNumbered(const std::string&key, const int no, T&t) {
336   // Check keyword has been registered
337   plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered");
338   if( !keywords.numbered(key) ) error("numbered keywords are not allowed for " + key );
339 
340   // Now try to read the keyword
341   std::string num; Tools::convert(no,num);
342   return Tools::parse(line,key+num,t,replica_index);
343 }
344 
345 template<class T>
parseVector(const std::string & key,std::vector<T> & t)346 void Action::parseVector(const std::string&key,std::vector<T>&t) {
347 //  if(!Tools::parseVector(line,key,t)){
348 //    log.printf("ERROR parsing keyword %s\n",key.c_str());
349 //    log.printf("%s\n",getDocumentation().c_str());
350 //    this->exit(1);
351 //  }
352 
353   // Check keyword has been registered
354   plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered");
355   unsigned size=t.size(); bool skipcheck=false;
356   if(size==0) skipcheck=true;
357 
358   // Now try to read the keyword
359   std::string def; T val;
360   bool present=Tools::findKeyword(line,key);
361   bool found=Tools::parseVector(line,key,t,replica_index);
362   if(present && !found) error("keyword " + key +" could not be read correctly");
363 
364   // Check vectors size is correct (not if this is atoms or ARG)
365   if( !keywords.style(key,"atoms") && found ) {
366 //     bool skipcheck=false;
367 //     if( keywords.style(key,"compulsory") ){ keywords.getDefaultValue(key,def); skipcheck=(def=="nosize"); }
368     if( !skipcheck && t.size()!=size ) error("vector read in for keyword " + key + " has the wrong size");
369   }
370 
371   // If it isn't read and it is compulsory see if a default value was specified
372   if ( !found && (keywords.style(key,"compulsory") || keywords.style(key,"hidden")) ) {
373     if( keywords.getDefaultValue(key,def) ) {
374       if( def.length()==0 || !Tools::convert(def,val) ) {
375         log.printf("ERROR in action %s with label %s : keyword %s has weird default value",name.c_str(),label.c_str(),key.c_str() );
376         this->exit(1);
377       } else {
378         if(t.size()>0) for(unsigned i=0; i<t.size(); ++i) t[i]=val;
379         else t.push_back(val);
380       }
381     } else if( keywords.style(key,"compulsory") ) {
382       error("keyword " + key + " is compulsory for this action");
383     }
384   } else if ( !found ) {
385     t.resize(0);
386   }
387 }
388 
389 template<class T>
parseNumberedVector(const std::string & key,const int no,std::vector<T> & t)390 bool Action::parseNumberedVector(const std::string&key, const int no, std::vector<T>&t) {
391   plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered");
392   if( !keywords.numbered(key) ) error("numbered keywords are not allowed for " + key );
393 
394   unsigned size=t.size(); bool skipcheck=false;
395   if(size==0) skipcheck=true;
396   std::string num; Tools::convert(no,num);
397   bool present=Tools::findKeyword(line,key);
398   bool found=Tools::parseVector(line,key+num,t,replica_index);
399   if(present && !found) error("keyword " + key +" could not be read correctly");
400 
401   if(  keywords.style(key,"compulsory") ) {
402     if (!skipcheck && found && t.size()!=size ) error("vector read in for keyword " + key + num + " has the wrong size");
403   } else if ( !found ) {
404     t.resize(0);
405   }
406   return found;
407 }
408 
409 inline
deactivate()410 void Action::deactivate() {
411   options.clear();
412   active=false;
413 }
414 
415 inline
isActive()416 bool Action::isActive()const {
417   return active;
418 }
419 
420 inline
isOptionOn(const std::string & s)421 bool Action::isOptionOn(const std::string &s)const {
422   return options.count(s);
423 }
424 
425 inline
getRestart()426 bool Action::getRestart()const {
427   return restart;
428 }
429 
430 }
431 #endif
432 
433