From 06822905fc2542854378ad1fd56c6b4bad001bcd Mon Sep 17 00:00:00 2001
From: Gareth Tribello <gareth.tribello@gmail.com>
Date: Wed, 15 Feb 2012 21:22:42 +0100
Subject: [PATCH] You can now reserve keywords so that they can only ever be
 used for specific tasks.  To reserve a keyword use keys.reserve() and to then
 use it later use keys.user().  Currently the reserved keywords are ARG and
 PERIODIC.

---
 developer-doc/usingDoxygen.txt | 14 ++++++++++++++
 src/ActionWithArguments.cpp    | 24 ++++++++++++------------
 src/ActionWithArguments.h      |  9 ++++++---
 src/BiasExternal.cpp           |  1 +
 src/BiasLWalls.cpp             |  1 +
 src/BiasMetaD.cpp              |  1 +
 src/BiasMovingRestraint.cpp    |  1 +
 src/BiasRatchet.cpp            |  1 +
 src/BiasRestraint.cpp          |  1 +
 src/BiasUWalls.cpp             |  1 +
 src/Function.cpp               | 28 +++++++++++++++++++---------
 src/FunctionCombine.cpp        | 11 -----------
 src/FunctionMatheval.cpp       | 12 ------------
 src/GenericDumpDerivatives.cpp |  1 +
 src/GenericDumpForces.cpp      |  1 +
 src/GenericPrint.cpp           |  1 +
 src/Keywords.cpp               | 28 ++++++++++++++++++++++++++++
 src/Keywords.h                 | 12 ++++++++++++
 18 files changed, 101 insertions(+), 47 deletions(-)

diff --git a/developer-doc/usingDoxygen.txt b/developer-doc/usingDoxygen.txt
index 17faf1500..f115a9c3c 100644
--- a/developer-doc/usingDoxygen.txt
+++ b/developer-doc/usingDoxygen.txt
@@ -100,6 +100,20 @@ compulsory keyword and do not specify a default value then the code will automat
 In addition, if the vector you pass to PLMD::Action::parseVector and PLMD::Action::parseNumberedVector has a
 size greater than 0 plumed will assume that the input should contain a vector of this size and will complain if it finds a different sized vector.
 
+\section reserved Reserved Keywords
+
+To maintain some consistency for end users of the code certain keywords (e.g. ARG, PERIODIC) are reserved.
+The reserved keywords for PLMD::Colvar, PLMD::Function and PLMD::Bias are explained inside the documentation for
+these actions.  To use one of the registered keywords you shold insert the following command into the registerKeywords
+method of your new function.
+
+\verbatim
+keys.use( keyword );
+\endverbatim
+
+where <i> keyword </i> is a string that tells the method which reserved keyword you wish to use.  To be clear
+when you use a reserved keyword all the parsing and registering for it is looked after automatically.
+
 \section errors Generating errors
 
 You may need to check for other mistakes in input.  When you find these mistakes you can report them to users using PLMD::Action::error.  This routine will 
diff --git a/src/ActionWithArguments.cpp b/src/ActionWithArguments.cpp
index 020d179bd..48da48e23 100644
--- a/src/ActionWithArguments.cpp
+++ b/src/ActionWithArguments.cpp
@@ -7,7 +7,7 @@ using namespace std;
 using namespace PLMD;
 
 void ActionWithArguments::registerKeywords(Keywords& keys){
-  keys.add("compulsory","ARG","the input for this action is the output from one or more other actions. The particular output that you used is referenced using that action of interests label. If the label appears on its own then the default output is taken.  If * appears then the default output from all actions is taken.  Some actions have multi-component outputs, each component of the output has a specific label so for instance an action labelled dist may have three componets x, y and z.  To take just the x component you should use dist.x, if you wish to take all three components then use dist.*");
+  keys.reserve("compulsory","ARG","the input for this action is the output from one or more other actions. The particular output that you used is referenced using that action of interests label. If the label appears on its own then the value of the relevant Action is taken.  If * or *.* appears the information from all arguments is taken.  Some actions have multi-component outputs, each component of the output has a specific label so for instance an action labelled dist may have three componets x, y and z.  To take just the x component you should use dist.x, if you wish to take all three components then use dist.*");
 }
 
 void ActionWithArguments::parseArgumentList(const std::string&key,std::vector<Value*>&arg){
@@ -79,7 +79,7 @@ void ActionWithArguments::requestArguments(const vector<Value*> &arg){
        name=fullname;
      }
      ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(name);
-     if(!action) error("cannot find action named (in requestArguments - this is weird)" + name);
+     plumed_massert(action,"cannot find action named (in requestArguments - this is weird)" + name);
      addDependency(action);
   }
 }
@@ -88,17 +88,17 @@ ActionWithArguments::ActionWithArguments(const ActionOptions&ao):
   Action(ao),
   lockRequestArguments(false)
 {
-  vector<Value*> arg;
-  parseArgumentList("ARG",arg);
-
-  if(arg.size()>0){
-    log.printf("  with arguments");
-    for(unsigned i=0;i<arg.size();i++) log.printf(" %s",arg[i]->getName().c_str());
-    log.printf("\n");
+  if( keywords.exists("ARG") ){
+     vector<Value*> arg;
+     parseArgumentList("ARG",arg);
+
+     if(arg.size()>0){
+       log.printf("  with arguments");
+       for(unsigned i=0;i<arg.size();i++) log.printf(" %s",arg[i]->getName().c_str());
+       log.printf("\n");
+     }
+     requestArguments(arg);
   }
-
-  requestArguments(arg);
-
 }
 
 void ActionWithArguments::calculateNumericalDerivatives(){
diff --git a/src/ActionWithArguments.h b/src/ActionWithArguments.h
index dc87a4547..e55ff9a0a 100644
--- a/src/ActionWithArguments.h
+++ b/src/ActionWithArguments.h
@@ -14,9 +14,12 @@ This is used in PLMD::Function and PLMD::Bias
 */
 //+ENDDEVELDOC
 
-/// Action which takes other Action's as arguments.
-/// Arguments are objects of type PLMD::Value, and
-/// are addressed using the ARG= keyword on the directive line
+/// PLMD::Action objects that inherit from PLMD::ActionWithArguments take 
+/// values and components calculated in other PLMD::Action objects and
+/// use this information to calculate some new function.  If you have 
+/// only one list of arguments you should use the reserved keyword <b> ARG </b> 
+/// when you use parseArgumentList.
+
 class ActionWithArguments:
   public virtual Action
 {
diff --git a/src/BiasExternal.cpp b/src/BiasExternal.cpp
index b20aa37fd..3fd4320da 100644
--- a/src/BiasExternal.cpp
+++ b/src/BiasExternal.cpp
@@ -42,6 +42,7 @@ PLUMED_REGISTER_ACTION(BiasExternal,"EXTERNAL")
 
 void BiasExternal::registerKeywords(Keywords& keys){
   Bias::registerKeywords(keys);
+  keys.use("ARG");
   keys.add("compulsory","FILE","the name of the file containing the external potential");
   keys.addFlag("NOSPLINE",false,"specifies that no spline interpolation is to be used when calculating the energy and forces due to the external potential");
   keys.addFlag("SPARSE",false,"specifies that the external potential uses a sparse grid");
diff --git a/src/BiasLWalls.cpp b/src/BiasLWalls.cpp
index dae30cc60..b4139bb78 100644
--- a/src/BiasLWalls.cpp
+++ b/src/BiasLWalls.cpp
@@ -54,6 +54,7 @@ PLUMED_REGISTER_ACTION(BiasLWalls,"LOWER_WALLS")
 
 void BiasLWalls::registerKeywords(Keywords& keys){
   Bias::registerKeywords(keys);
+  keys.use("ARG");
   keys.add("compulsory","AT","the positions of the wall. The a_i in the expression for a wall.");
   keys.add("compulsory","KAPPA","the force constant for the wall.  The k_i in the expression for a wall.");
   keys.add("compulsory","OFFSET","0.0","the offset for the start of the wall.  The o_i in the expression for a wall.");
diff --git a/src/BiasMetaD.cpp b/src/BiasMetaD.cpp
index cd442db20..ab152cb81 100644
--- a/src/BiasMetaD.cpp
+++ b/src/BiasMetaD.cpp
@@ -115,6 +115,7 @@ PLUMED_REGISTER_ACTION(BiasMetaD,"METAD")
 
 void BiasMetaD::registerKeywords(Keywords& keys){
   Bias::registerKeywords(keys);
+  keys.use("ARG");
   keys.add("compulsory","SIGMA","the widths of the Gaussian hills");
   keys.add("compulsory","HEIGHT","the heights of the Gaussian hills");
   keys.add("compulsory","PACE","the frequency for hill addition");
diff --git a/src/BiasMovingRestraint.cpp b/src/BiasMovingRestraint.cpp
index 8b5fcff9f..bcc76bb53 100644
--- a/src/BiasMovingRestraint.cpp
+++ b/src/BiasMovingRestraint.cpp
@@ -92,6 +92,7 @@ PLUMED_REGISTER_ACTION(BiasMovingRestraint,"MOVINGRESTRAINT")
 
 void BiasMovingRestraint::registerKeywords( Keywords& keys ){
   Bias::registerKeywords(keys);
+  keys.use("ARG");
   keys.add("compulsory","VERSE","B","Tells plumed whether the restraint is only acting for CV larger (U) or smaller (L) than the restraint or whether it is acting on both sides (B)");
   keys.add("numbered","STEP","This keyword appears multiple times as STEPx with x=0,1,2,...,n.  Each value given represents the MD step at which the restraint parameters take the values KAPPAx and ATx.");
   keys.add("numbered","AT","ATx is equal to the position of the restraint at time STEPx.  For intermediate times this parameter is linearly interpolated.  If no ATx is specified for STEPx then the values of AT are kept constant during the interval of time between STEPx-1 and STEPx.");
diff --git a/src/BiasRatchet.cpp b/src/BiasRatchet.cpp
index 8480557cb..e65bb71c3 100644
--- a/src/BiasRatchet.cpp
+++ b/src/BiasRatchet.cpp
@@ -58,6 +58,7 @@ PLUMED_REGISTER_ACTION(BiasRatchet,"ABMD")
 
 void BiasRatchet::registerKeywords(Keywords& keys){
   Bias::registerKeywords(keys);
+  keys.use("ARG");
   keys.add("compulsory","TO","The array of a values in the above equation");
   keys.add("compulsory","KAPPA","The array of force constants.");
   keys.add("compulsory","MIN","Also the array of a values in the above equation - I don't understand.");
diff --git a/src/BiasRestraint.cpp b/src/BiasRestraint.cpp
index 48f025607..5870073b0 100644
--- a/src/BiasRestraint.cpp
+++ b/src/BiasRestraint.cpp
@@ -51,6 +51,7 @@ PLUMED_REGISTER_ACTION(BiasRestraint,"RESTRAINT")
 
 void BiasRestraint::registerKeywords(Keywords& keys){
    Bias::registerKeywords(keys);
+   keys.use("ARG");
    keys.add("compulsory","SLOPE","0.0","specifies that the restraint is linear and what the values of the force constants on each of the variables are");
    keys.add("compulsory","KAPPA","0.0","specifies that the restraint is harmonic and what the values of the force constants on each of the variables are");
    keys.add("compulsory","AT","the position of the restraint");
diff --git a/src/BiasUWalls.cpp b/src/BiasUWalls.cpp
index 41d6a45d5..fc60c4781 100644
--- a/src/BiasUWalls.cpp
+++ b/src/BiasUWalls.cpp
@@ -54,6 +54,7 @@ PLUMED_REGISTER_ACTION(BiasUWalls,"UPPER_WALLS")
 
 void BiasUWalls::registerKeywords(Keywords& keys){
   Bias::registerKeywords(keys);
+  keys.use("ARG");
   keys.add("compulsory","AT","the positions of the wall. The a_i in the expression for a wall.");
   keys.add("compulsory","KAPPA","the force constant for the wall.  The k_i in the expression for a wall.");
   keys.add("compulsory","OFFSET","0.0","the offset for the start of the wall.  The o_i in the expression for a wall.");
diff --git a/src/Function.cpp b/src/Function.cpp
index b77092de7..682fb7eb1 100644
--- a/src/Function.cpp
+++ b/src/Function.cpp
@@ -4,6 +4,13 @@
 using namespace PLMD;
 using namespace std;
 
+void Function::registerKeywords(Keywords& keys){
+  Action::registerKeywords(keys);
+  ActionWithValue::registerKeywords(keys);
+  ActionWithArguments::registerKeywords(keys);
+  keys.reserve("compulsory","PERIODIC","if the output of your function is periodic then you should specify the periodicity of the function.  If the output is not periodic you must state this using PERIODIC=NO");
+}
+
 Function::Function(const ActionOptions&ao):
 Action(ao),
 ActionWithValue(ao),
@@ -15,6 +22,18 @@ void Function::addValueWithDerivatives(){
   plumed_massert( getNumberOfArguments()!=0, "for functions you must requestArguments before adding values");
   ActionWithValue::addValueWithDerivatives();  
   getPntrToValue()->resizeDerivatives(getNumberOfArguments());
+
+  if( keywords.exists("PERIODIC") ){
+     double min(0),max(0); std::vector<std::string> period;  
+     parseVector("PERIODIC",period);  
+     if(period.size()==1 && period[0]=="NO"){
+        setNotPeriodic();
+     } else if(period.size()==2 && Tools::convert(period[0],min) && Tools::convert(period[1],max)){
+        setPeriodic(min,max);
+     } else error("missing PERIODIC keyword");
+  } else {
+     plumed_massert(0,"You should use the reserved keyword PERIODIC to read in the periodicity for single value functions");
+  }
 } 
   
 void Function::addComponentWithDerivatives( const std::string& name ){
@@ -40,12 +59,3 @@ void Function::apply(){
     getPntrToArgument(i)->addForce(f[i]);
   }
 }
-
-void Function::registerKeywords(Keywords& keys){
-  Action::registerKeywords(keys);
-  ActionWithValue::registerKeywords(keys);
-  ActionWithArguments::registerKeywords(keys);
-  keys.reserve("compulsory","PERIODIC","if the output of your function is periodic then you should specify the periodicity of the function.  If the output is not periodic you must state this using PERIODIC=NO");
-}
-
-
diff --git a/src/FunctionCombine.cpp b/src/FunctionCombine.cpp
index e9ea9e021..ccda34cd7 100644
--- a/src/FunctionCombine.cpp
+++ b/src/FunctionCombine.cpp
@@ -73,18 +73,7 @@ powers(getNumberOfArguments(),1.0)
     for(unsigned i=0;i<coefficients.size();i++) coefficients[i]*=(1.0/n);
   }
  
-<<<<<<< HEAD
-  addValueWithDerivatives(); getPntrToComponent(0)->resizeDerivatives(getNumberOfArguments());
-=======
   addValueWithDerivatives(); 
->>>>>>> 6166262... Made it so that we don't have to resize the values in the individual
-  double min(0),max(0); std::vector<std::string> period;
-  parseVector("PERIODIC",period);
-  if(period.size()==1 && period[0]=="NO"){
-     setNotPeriodic();
-  } else if(period.size()==2 && Tools::convert(period[0],min) && Tools::convert(period[1],max)){
-     setPeriodic(min,max);
-  } else error("missing PERIODIC keyword");
   checkRead();
 
   log.printf("  with coefficients:");
diff --git a/src/FunctionMatheval.cpp b/src/FunctionMatheval.cpp
index 970c51abc..b58f73a1a 100644
--- a/src/FunctionMatheval.cpp
+++ b/src/FunctionMatheval.cpp
@@ -65,7 +65,6 @@ void FunctionMatheval::registerKeywords(Keywords& keys){
   keys.use("ARG"); keys.use("PERIODIC");
   keys.add("compulsory","FUNC","the function you wish to evaluate");
   keys.add("optional","VAR","the names to give each of the arguments in the function.  If you have up to three arguments in your function you can use x, y and z to refer to them.  Otherwise you must use this flag to give your variables names.");
-
 }
 
 FunctionMatheval::FunctionMatheval(const ActionOptions&ao):
@@ -85,18 +84,7 @@ names(getNumberOfArguments())
   }
   assert(var.size()==getNumberOfArguments());
   parse("FUNC",func);
-<<<<<<< HEAD
-  addValueWithDerivatives(); getPntrToComponent(0)->resizeDerivatives(getNumberOfArguments());
-=======
   addValueWithDerivatives(); 
->>>>>>> 6166262... Made it so that we don't have to resize the values in the individual
-  double min(0),max(0); std::vector<std::string> period;
-  parseVector("PERIODIC",period);
-  if(period.size()==1 && period[0]=="NO"){
-    setNotPeriodic();
-  } else if(period.size()==2 && Tools::convert(period[0],min) && Tools::convert(period[1],max)){
-    setPeriodic(min,max);
-  } else error("missing PERIODIC keyword");
   checkRead();
 
   evaluator=evaluator_create(const_cast<char*>(func.c_str()));
diff --git a/src/GenericDumpDerivatives.cpp b/src/GenericDumpDerivatives.cpp
index 127a687b9..35609c074 100644
--- a/src/GenericDumpDerivatives.cpp
+++ b/src/GenericDumpDerivatives.cpp
@@ -53,6 +53,7 @@ void GenericDumpDerivatives::registerKeywords(Keywords& keys){
   Action::registerKeywords(keys);
   ActionPilot::registerKeywords(keys);
   ActionWithArguments::registerKeywords(keys);
+  keys.use("ARG");
   keys.add("compulsory","STRIDE","1","the frequency with which the derivatives should be output");
   keys.add("compulsory","FILE","the name of the file on which to output the derivatives");
   keys.add("compulsory","FMT","%15.10f","the format with which the derivatives should be output");
diff --git a/src/GenericDumpForces.cpp b/src/GenericDumpForces.cpp
index 2cde9f245..cd5c090f6 100644
--- a/src/GenericDumpForces.cpp
+++ b/src/GenericDumpForces.cpp
@@ -53,6 +53,7 @@ void GenericDumpForces::registerKeywords(Keywords& keys){
   Action::registerKeywords(keys);
   ActionPilot::registerKeywords(keys);
   ActionWithArguments::registerKeywords(keys);
+  keys.use("ARG");
   keys.add("compulsory","STRIDE","1","the frequency with which the forces should be output");
   keys.add("compulsory","FILE","the name of the file on which to output the forces");
 }
diff --git a/src/GenericPrint.cpp b/src/GenericPrint.cpp
index 5dbab1f0e..221f5ba12 100644
--- a/src/GenericPrint.cpp
+++ b/src/GenericPrint.cpp
@@ -60,6 +60,7 @@ void GenericPrint::registerKeywords(Keywords& keys){
   Action::registerKeywords(keys);
   ActionPilot::registerKeywords(keys);
   ActionWithArguments::registerKeywords(keys);
+  keys.use("ARG");
   keys.add("compulsory","STRIDE","1","the frequency with which the quantities of interest should be output");
   keys.add("compulsory","FILE","the name of the file on which to output these quantities");
   keys.add("optional","FMT","the format that should be used to output real numbers");
diff --git a/src/Keywords.cpp b/src/Keywords.cpp
index 1b7042ae4..11f83509f 100644
--- a/src/Keywords.cpp
+++ b/src/Keywords.cpp
@@ -22,14 +22,31 @@ KeyType::KeyType( const std::string& type ){
   }
 }
 
+void Keywords::reserve( const std::string t, const std::string k, const std::string d ){
+  plumed_assert( !exists(k) );  plumed_assert( t!="flag");  // Cannot reserve flags at the moment - if you need it let me know
+  plumed_assert( !reserved(k) );
+  reserved_types.push_back( KeyType(t) ); reserved_keys.push_back(k); reserved_documentation.push_back(d);
+}
+
+void Keywords::use( const std::string k ){
+  plumed_assert( reserved(k) );
+  for(unsigned i=0;i<reserved_keys.size();++i){
+     if(reserved_keys[i]==k){ 
+       types.push_back( reserved_types[i] ); keys.push_back( reserved_keys[i] ); documentation.push_back( reserved_documentation[i] );
+     }
+  }
+}
+
 void Keywords::add( const std::string t, const std::string k, const std::string d ){
   plumed_assert( !exists(k) ); plumed_assert( t!="flag");  // Use addFlag to add flags
+  plumed_assert( !reserved(k) );
   types.push_back( KeyType(t) ); keys.push_back(k); documentation.push_back(d); 
   //defaults.push_back(false);
 }
 
 void Keywords::add( const std::string t, const std::string k, const std::string  def, const std::string d ){
   plumed_assert( !exists(k) ); plumed_assert( t=="compulsory" ); // An optional keyword can't have a default
+  plumed_assert( !reserved(k) );
   types.push_back( KeyType(t) ); keys.push_back(k); 
   documentation.push_back( "( default=" + def + " ) " + d ); 
   numdefs.insert( std::pair<std::string,std::string>(k,def) );
@@ -37,6 +54,7 @@ void Keywords::add( const std::string t, const std::string k, const std::string
 
 void Keywords::addFlag( const std::string k, const bool def, const std::string d ){
   plumed_assert( !exists(k) ); std::string defstr, flag="flag";
+  plumed_assert( !reserved(k) );
   if( def ) { defstr="( default=on ) "; } else { defstr="( default=off ) "; }
   types.push_back( KeyType(flag) ); keys.push_back(k); documentation.push_back( defstr + d ); //defaults.push_back(def);
   booldefs.insert( std::pair<std::string,bool>(k,def) );
@@ -122,6 +140,16 @@ bool Keywords::exists( const std::string k ) const {
   return false;
 }
 
+bool Keywords::reserved( const std::string k ) const {
+  plumed_massert( reserved_keys.size()==reserved_documentation.size(), "documentation doesn't match keys" );
+  plumed_massert( reserved_keys.size()==reserved_types.size(), "types doesn't match keys" );
+
+  for(unsigned i=0;i<reserved_keys.size();++i){
+     if( reserved_keys[i]==k ) return true;
+  }
+  return false;
+}
+
 void Keywords::print_html() const {
   unsigned nkeys=0;
   for(unsigned i=0;i<keys.size();++i){
diff --git a/src/Keywords.h b/src/Keywords.h
index 9e697cff2..3af6b06ff 100644
--- a/src/Keywords.h
+++ b/src/Keywords.h
@@ -30,6 +30,12 @@ public:
 class Keywords{
 friend class Action;
 private:
+/// Whether the keyword is compulsory, optional...
+  std::vector<KeyType> reserved_types;
+/// The names of the keyword
+  std::vector<std::string> reserved_keys;
+/// The documentation for the keywords
+  std::vector<std::string> reserved_documentation;
 /// Whether the keyword is compulsory, optional...
   std::vector<KeyType> types;
 /// The names of the keyword
@@ -53,6 +59,10 @@ private:
 /// Return the number of defined keywords 
   unsigned size() const;
 public:
+/// Reserve a keyword 
+  void reserve( const std::string t, const std::string k, const std::string d );
+/// Use one of the reserved keywords
+  void use( const std::string k );
 /// Add a new keyword of type t with name k and description d
   void add( const std::string t, const std::string k, const std::string d );
 /// Add a new compulsory keyword (t must equal compulsory) with name k, default value def and description d
@@ -67,6 +77,8 @@ public:
 //   unsigned size() const;
 /// Check if there is a keyword with name k
   bool exists( const std::string k ) const ;
+/// Check the keyword k has been reserved
+  bool reserved( const std::string k ) const ;
 /// Check if the keyword with name k has style t
   bool style( const std::string k, const std::string t ) const ;
 // /// Print the documentation to the log file (used by PLMD::Action::error)
-- 
GitLab