All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ActionWithArguments.cpp
Go to the documentation of this file.
1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2  Copyright (c) 2013 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-code.org for more information.
6 
7  This file is part of plumed, version 2.0.
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 "ActionWithArguments.h"
23 #include "ActionWithValue.h"
24 #include "tools/PDB.h"
25 #include "PlumedMain.h"
26 #include "ActionSet.h"
27 #include <iostream>
28 #ifdef __PLUMED_HAS_CREGEX
29 #include <cstring>
30 #include "regex.h"
31 #endif
32 
33 using namespace std;
34 namespace PLMD{
35 
36 void ActionWithArguments::registerKeywords(Keywords& keys){
37  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.*");
38 }
39 
40 void ActionWithArguments::parseArgumentList(const std::string&key,std::vector<Value*>&arg){
41  vector<string> c; arg.clear(); parseVector(key,c); interpretArgumentList(c,arg);
42 }
43 
44 void ActionWithArguments::interpretArgumentList(const std::vector<std::string>& c, std::vector<Value*>&arg){
45 
46  for(unsigned i=0;i<c.size();i++){
47  // is a regex? then just interpret it. The signal is ()
48  std::size_t found1 = c[i].find("(");
49  std::size_t found2 ;
50  if(found1!=std::string::npos){
51  found2=c[i].find(")",found1+1,1); // find it again
52  if(found2!=std::string::npos){
53  // start regex parsing
54 #ifdef __PLUMED_HAS_CREGEX
55  // take the string enclosed in quotes and put in round brackets
56  std::string myregex=c[i].substr(found1,found2-found1+1);
57  log.printf(" Evaluating regexp for this action: %s \n",myregex.c_str());
58  int errcode;
59  regex_t *preg = (regex_t*)malloc(sizeof(regex_t)); // pointer to the regular expression
60  regmatch_t *pmatch;
61  if ((errcode=regcomp(preg, myregex.c_str() ,REG_EXTENDED|REG_NEWLINE))) { // compile the regular expression
62  char* errbuf;
63  size_t errbuf_size;
64  // one can check the errors asking to regerror
65  errbuf_size = regerror(errcode, preg, NULL, 0);
66  if (!(errbuf=(char*)malloc(errbuf_size))) {
67  plumed_merror("cannot allocate the buffer for error detection in regexp!");
68  };
69  regerror(errcode, preg, errbuf, errbuf_size);
70  error(errbuf);
71  }
72  plumed_massert(preg->re_nsub==1,"I can parse with only one subexpression");
73  pmatch = (regmatch_t*)malloc(sizeof(regmatch_t)*preg->re_nsub);
74  // select all the actions that have a value
75  std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>();
76  if( all.empty() ) error("your input file is not telling plumed to calculate anything");
77  for(unsigned j=0;j<all.size();j++){
78  std::string thisargument=all[j]->getLabel();
79  std::vector<std::string> ss=all[j]->getComponentsVector();
80  for(unsigned k=0;k<ss.size();++k){
81  thisargument=ss[k];
82  unsigned ll=strlen(ss[k].c_str())+1;
83  char*str;
84  str=new char [ll];
85  strcpy(str,ss[k].c_str());
86  char *ppstr=str;
87  if(!regexec(preg, ppstr , preg->re_nsub, pmatch, 0)) {
88  log.printf(" Something matched with \"%s\" : ",ss[k].c_str());
89  do {
90  if (pmatch[0].rm_so != -1) { /* The regex is matching part of a string */
91  char *submatch;
92  size_t matchlen = pmatch[0].rm_eo - pmatch[0].rm_so;
93  submatch = (char*)malloc(matchlen+1);
94  strncpy(submatch, ppstr+pmatch[0].rm_so, matchlen+1);
95  submatch[matchlen]='\0';
96  log.printf(" subpattern %s\n", submatch);
97  // this is the match: try to see if it is a valid action
98  std::string putativeVal(submatch);
99  if( all[j]->exists(putativeVal) ){
100  arg.push_back(all[j]->copyOutput(putativeVal));
101  log.printf(" Action %s added! \n",putativeVal.c_str());
102  }
103  free(submatch);
104  };
105  ppstr += pmatch[0].rm_eo; /* Restart from last match */
106  } while(!regexec(preg,ppstr,preg->re_nsub,pmatch,0));
107  }
108  delete [] str;
109  }
110  };
111  regfree(preg);
112  free(preg);
113  free(pmatch);
114 #else
115  plumed_merror("Regexp support not compiled!");
116 #endif
117  }else{
118  plumed_merror("did you want to use regexp to input arguments? enclose it between two round braces (...) with no spaces!");
119  }
120  }else{
121  std::size_t dot=c[i].find_first_of('.');
122  string a=c[i].substr(0,dot);
123  string name=c[i].substr(dot+1);
124  if(c[i].find(".")!=string::npos){ // if it contains a dot:
125  if(a=="*" && name=="*"){
126  // Take all values from all actions
127  std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>();
128  if( all.empty() ) error("your input file is not telling plumed to calculate anything");
129  for(unsigned j=0;j<all.size();j++){
130  for(int k=0;k<all[j]->getNumberOfComponents();++k) arg.push_back(all[j]->copyOutput(k));
131  }
132  } else if ( name=="*"){
133  // Take all the values from an action with a specific name
134  ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(a);
135  if(!action){
136  std::string str=" (hint! the actions in this ActionSet are: ";
137  str+=plumed.getActionSet().getLabelList()+")";
138  error("cannot find action named " + a + str);
139  }
140  for(int k=0;k<action->getNumberOfComponents();++k) arg.push_back(action->copyOutput(k));
141  } else if ( a=="*" ){
142  // Take components from all actions with a specific name
143  std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>();
144  if( all.empty() ) error("your input file is not telling plumed to calculate anything");
145  unsigned nval=0;
146  for(unsigned j=0;j<all.size();j++){
147  std::string flab; flab=all[j]->getLabel() + "." + name;
148  if( all[j]->exists(flab) ){ arg.push_back(all[j]->copyOutput(flab)); nval++; }
149  }
150  if(nval==0) error("found no actions with a component called " + name );
151  } else {
152  // Take values with a specific name
153  ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(a);
154  if(!action){
155  std::string str=" (hint! the actions in this ActionSet are: ";
156  str+=plumed.getActionSet().getLabelList()+")";
157  error("cannot find action named " + a +str);
158  }
159  if( !(action->exists(c[i])) ){
160  std::string str=" (hint! the components in this actions are: ";
161  str+=action->getComponentsList()+")";
162  error("action " + a + " has no component named " + name + str);
163  } ;
164  arg.push_back(action->copyOutput(c[i]));
165  }
166  } else { // if it doesn't contain a dot
167  if(c[i]=="*"){
168  // Take all values from all actions
169  std::vector<ActionWithValue*> all=plumed.getActionSet().select<ActionWithValue*>();
170  if( all.empty() ) error("your input file is not telling plumed to calculate anything");
171  for(unsigned j=0;j<all.size();j++){
172  for(int k=0;k<all[j]->getNumberOfComponents();++k) arg.push_back(all[j]->copyOutput(k));
173  }
174  } else {
175  ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(c[i]);
176  if(!action){
177  std::string str=" (hint! the actions in this ActionSet are: ";
178  str+=plumed.getActionSet().getLabelList()+")";
179  error("cannot find action named " + c[i] + str );
180  }
181  if( !(action->exists(c[i])) ){
182  std::string str=" (hint! the components in this actions are: ";
183  str+=action->getComponentsList()+")";
184  error("action " + c[i] + " has no component named " + c[i] +str);
185  };
186  arg.push_back(action->copyOutput(c[i]));
187  }
188  }
189  }
190  }
191 }
192 
193 void ActionWithArguments::expandArgKeywordInPDB( PDB& pdb ){
194  std::vector<std::string> pdb_remark=pdb.getRemark();
195  std::vector<std::string> arg_names;
196  bool found=Tools::parseVector(pdb_remark,"ARG",arg_names);
197  if( found ){
198  std::vector<Value*> arg_vals;
199  interpretArgumentList( arg_names, arg_vals );
200  std::string new_args="ARG=" + arg_vals[0]->getName();
201  for(unsigned i=1;i<arg_vals.size();++i) new_args = new_args + "," + arg_vals[i]->getName();
202  pdb.setArgKeyword( new_args );
203  }
204 }
205 
206 void ActionWithArguments::requestArguments(const vector<Value*> &arg){
207  plumed_massert(!lockRequestArguments,"requested argument list can only be changed in the prepare() method");
208  arguments=arg;
209  clearDependencies();
210  std::string fullname,name;
211  for(unsigned i=0;i<arguments.size();i++){
212  fullname=arguments[i]->getName();
213  if(fullname.find(".")!=string::npos){
214  std::size_t dot=fullname.find_first_of('.');
215  name=fullname.substr(0,dot);
216  } else {
217  name=fullname;
218  }
219  ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>(name);
220  plumed_massert(action,"cannot find action named (in requestArguments - this is weird)" + name);
221  addDependency(action);
222  }
223 }
224 
225 ActionWithArguments::ActionWithArguments(const ActionOptions&ao):
226  Action(ao),
227  lockRequestArguments(false)
228 {
229  if( keywords.exists("ARG") ){
230  vector<Value*> arg;
231  parseArgumentList("ARG",arg);
232 
233  if(!arg.empty()){
234  log.printf(" with arguments");
235  for(unsigned i=0;i<arg.size();i++) log.printf(" %s",arg[i]->getName().c_str());
236  log.printf("\n");
237  }
238  requestArguments(arg);
239  }
240 }
241 
243  if(!a){
244  a=dynamic_cast<ActionWithValue*>(this);
245  plumed_massert(a,"cannot compute numerical derivatives for an action without values");
246  }
247 
248  const int nval=a->getNumberOfComponents();
249  const int npar=arguments.size();
250  std::vector<double> value (nval*npar);
251  for(int i=0;i<npar;i++){
252  double arg0=arguments[i]->get();
253  arguments[i]->set(arg0+sqrt(epsilon));
254  a->calculate();
255  arguments[i]->set(arg0);
256  for(unsigned j=0;j<nval;j++){
257  value[i*nval+j]=a->getOutputQuantity(j);
258  }
259  }
260  a->calculate();
261  a->clearDerivatives();
262  for(unsigned j=0;j<nval;j++){
263  Value* v=a->copyOutput(j);
264  if( v->hasDerivatives() ) for(int i=0;i<npar;i++) v->addDerivative(i,(value[i*nval+j]-a->getOutputQuantity(j))/sqrt(epsilon));
265  }
266 }
267 
268 double ActionWithArguments::getProjection(unsigned i,unsigned j)const{
269  plumed_massert(i<arguments.size()," making projections with an index which is too large");
270  plumed_massert(j<arguments.size()," making projections with an index which is too large");
271  const Value* v1=arguments[i];
272  const Value* v2=arguments[j];
273  return Value::projection(*v1,*v2);
274 }
275 
276 void ActionWithArguments::addForcesOnArguments( const std::vector<double>& forces ){
277  for(unsigned i=0;i<arguments.size();++i) arguments[i]->addForce( forces[i] );
278 }
279 
280 }
virtual void calculateNumericalDerivatives(ActionWithValue *a=NULL)
Calculate the numerical derivatives N.B.
Log & log
Reference to the log stream.
Definition: Action.h:93
void parseArgumentList(const std::string &key, std::vector< Value * > &args)
Parse a list of arguments.
const double epsilon
A class for holding the value of a function together with its derivatives.
Definition: Value.h:46
void requestArguments(const std::vector< Value * > &arg)
Setup the dependencies.
STL namespace.
virtual void calculate()=0
Calculate an Action.
std::vector< Value * > arguments
Used to create a PLMD::Action that has some scalar or vectorial output that may or may not have some ...
void setArgKeyword(const std::string &new_args)
This is used to set the keyword ARG - this is so we we can use a1.
Definition: PDB.cpp:134
This class holds the keywords and their documentation.
Definition: Keywords.h:36
std::string getComponentsList() const
get a string that contains all the available components
bool exists(const std::string &name) const
Check if a value with a particular name is present.
This class is used to bring the relevant information to the Action constructor.
Definition: Action.h:41
void addForcesOnArguments(const std::vector< double > &forces)
Add forces to arguments (used in apply)
int printf(const char *fmt,...)
Formatted output with explicit format - a la printf.
Definition: OFile.cpp:82
Base class for all the input Actions.
Definition: Action.h:60
Value * copyOutput(const std::string &name) const
Return a pointer to the value with name (this is used to retrieve values in other PLMD::Actions) You ...
double getProjection(unsigned i, unsigned j) const
Get the scalar product between the gradients of two variables.
static double projection(const Value &, const Value &)
Definition: Value.cpp:140
void reserve(const std::string &t, const std::string &k, const std::string &d, const bool isvessel=false)
Reserve a keyword.
Definition: Keywords.cpp:110
Minimalistic pdb parser.
Definition: PDB.h:38
double getOutputQuantity(const unsigned j) const
Get the value of one of the components of the PLMD::Action.
const std::vector< std::string > & getRemark() const
Access to the lines of REMARK.
Definition: PDB.cpp:43
bool exists(const std::string &k) const
Check if there is a keyword with name k.
Definition: Keywords.cpp:239
virtual void clearDerivatives()
Clear the derivatives of values wrt parameters.
Main plumed object.
Definition: Plumed.h:201
int getNumberOfComponents() const
Returns the number of values defined.
void const char const char int double * a
Definition: Matrix.h:42
const Keywords & keywords
Definition: Action.h:161
void addDerivative(unsigned i, double d)
Add some derivative to the ith component of the derivatives array.
Definition: Value.h:224
bool hasDerivatives() const
Check whether or not this particular quantity has derivatives.
Definition: Value.h:213