All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ActionWithVessel.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 "tools/Communicator.h"
23 #include "ActionWithVessel.h"
24 #include "Vessel.h"
25 #include "ShortcutVessel.h"
26 #include "VesselRegister.h"
27 #include "BridgeVessel.h"
28 
29 using namespace std;
30 namespace PLMD{
31 namespace vesselbase{
32 
33 void ActionWithVessel::registerKeywords(Keywords& keys){
34  keys.add("optional","TOL","this keyword can be used to speed up your calculation. When accumulating sums in which the individual "
35  "terms are numbers inbetween zero and one it is assumed that terms less than a certain tolerance "
36  "make only a small contribution to the sum. They can thus be safely ignored as can the the derivatives "
37  "wrt these small quantities.");
38  keys.reserve("hidden","NL_TOL","this keyword can be used to speed up your calculation. It must be used in conjuction with the TOL "
39  "keyword and the value for NL_TOL must be set less than the value for TOL. This keyword ensures that "
40  "quantities, which are much less than TOL and which will thus not added to the sums being accumulated "
41  "are not calculated at every step. They are only calculated when the neighbor list is updated.");
42  keys.addFlag("SERIAL",false,"do the calculation in serial. Do not parallelize");
43  keys.add( vesselRegister().getKeywords() );
44 }
45 
46 ActionWithVessel::ActionWithVessel(const ActionOptions&ao):
47  Action(ao),
48  read(false),
49  serial(false),
50  contributorsAreUnlocked(false),
51  weightHasDerivatives(false)
52 {
53  if( keywords.exists("SERIAL") ) parseFlag("SERIAL",serial);
54  else serial=true;
55  if(serial)log.printf(" doing calculation in serial\n");
57  if( keywords.exists("TOL") ) parse("TOL",tolerance);
58  if( tolerance>epsilon){
59  if( keywords.exists("NL_TOL") ) parse("NL_TOL",nl_tolerance);
60  if( nl_tolerance>tolerance ) error("NL_TOL must be smaller than TOL");
61  log.printf(" Ignoring contributions less than %lf",tolerance);
62  if( nl_tolerance>epsilon ) log.printf(" and ignoring quantities less than %lf inbetween neighbor list update steps\n",nl_tolerance);
63  else log.printf("\n");
64  }
65  // Setup stuff for communicating what tasks have been deactivated across all nodes
67 }
68 
70  for(unsigned i=0;i<functions.size();++i) delete functions[i];
71 }
72 
73 void ActionWithVessel::addVessel( const std::string& name, const std::string& input, const int numlab, const std::string thislab ){
74  read=true; VesselOptions da(name,thislab,numlab,input,this);
75  Vessel* vv=vesselRegister().create(name,da); vv->checkRead();
76  addVessel(vv);
77 }
78 
80  ShortcutVessel* sv=dynamic_cast<ShortcutVessel*>(vv);
81  if(!sv) functions.push_back(vv);
82  else { delete sv; }
83 }
84 
86  read=true; VesselOptions da("","",0,"",this);
87  BridgeVessel* bv=new BridgeVessel(da);
88  bv->setOutputAction( tome );
89  functions.push_back( dynamic_cast<Vessel*>(bv) );
91  return bv;
92 }
93 
95  // Loop over all keywords find the vessels and create appropriate functions
96  for(unsigned i=0;i<keywords.size();++i){
97  std::string thiskey,input; thiskey=keywords.getKeyword(i);
98  // Check if this is a key for a vessel
99  if( vesselRegister().check(thiskey) ){
100  // If the keyword is a flag read it in as a flag
101  if( keywords.style(thiskey,"flag") ){
102  bool dothis; parseFlag(thiskey,dothis);
103  if(dothis) addVessel( thiskey, input );
104  // If it is numbered read it in as a numbered thing
105  } else if( keywords.numbered(thiskey) ) {
106  parse(thiskey,input);
107  if(input.size()!=0){
108  addVessel( thiskey, input );
109  } else {
110  for(unsigned i=1;;++i){
111  if( !parseNumbered(thiskey,i,input) ) break;
112  std::string ss; Tools::convert(i,ss);
113  addVessel( thiskey, input, i );
114  input.clear();
115  }
116  }
117  // Otherwise read in the keyword the normal way
118  } else {
119  parse(thiskey, input);
120  if(input.size()!=0) addVessel(thiskey,input);
121  }
122  input.clear();
123  }
124  }
125 
126  // Make sure all vessels have had been resized at start
127  if( functions.size()>0 ) resizeFunctions();
128 }
129 
131  unsigned tmpnval,nvals=2, bufsize=0;
132  for(unsigned i=0;i<functions.size();++i){
133  functions[i]->bufstart=bufsize;
134  functions[i]->resize();
135  bufsize+=functions[i]->bufsize;
136  tmpnval=functions[i]->getNumberOfTerms();
137  plumed_massert( tmpnval>1 , "There should always be at least two terms - one for the value and one for the weight");
138  if(tmpnval>nvals) nvals=tmpnval;
139  }
140  unsigned nder=getNumberOfDerivatives();
141  thisval.resize( nvals ); thisval_wasset.resize( nvals, false );
142  derivatives.resize( nvals*nder, 0.0 );
143  buffer.resize( bufsize );
144  tmpforces.resize( getNumberOfDerivatives() );
145 }
146 
148  plumed_dbg_assert( contributorsAreUnlocked );
149  for(unsigned i=0;i<taskList.fullSize();++i){
150  if( taskList(i)==current ) taskList.deactivate(i);
151  }
152 }
153 
154 //Vessel* ActionWithVessel::getVessel( const std::string& name ){
155 // std::string myname;
156 // for(unsigned i=0;i<functions.size();++i){
157 // if( functions[i]->getLabel(myname) ){
158 // if( myname==name ) return functions[i];
159 // }
160 // }
161 // error("there is no vessel with name " + name);
162 // return NULL;
163 //}
164 
166  // Clear all data from previous calculations
167  buffer.assign(buffer.size(),0.0);
168  // Do any preparatory stuff for functions
169  for(unsigned j=0;j<functions.size();++j) functions[j]->prepare();
170 }
171 
173  plumed_massert( read, "you must have a call to readVesselKeywords somewhere" );
174  unsigned stride=comm.Get_size();
175  unsigned rank=comm.Get_rank();
176  if(serial){ stride=1; rank=0; }
177 
178  // Make sure jobs are done
180 
181  for(unsigned i=rank;i<taskList.getNumberActive();i+=stride){
182  // Store the task we are currently working on
183  current=taskList[i];
184  // Calculate the stuff in the loop for this action
185  performTask(i);
186  // Weight should be between zero and one
187  plumed_dbg_assert( thisval[1]>=0 && thisval[1]<=1.0 );
188 
189  // Check for conditions that allow us to just to skip the calculation
190  // the condition is that the weight of the contribution is low
191  // N.B. Here weights are assumed to be between zero and one
192  if( thisval[1]<tolerance ){
193  // Clear the derivatives
194  clearAfterTask();
195  // Deactivate task if it is less than the neighbor list tolerance
197  continue;
198  }
199 
200  // Now calculate all the functions
201  // If the contribution of this quantity is very small at neighbour list time ignore it
202  // untill next neighbour list time
204  }
206 }
207 
209  // Clear the derivatives from this step
210  for(unsigned k=0;k<thisval.size();++k){
211  thisval_wasset[k]=false;
213  }
214 }
215 
216 void ActionWithVessel::clearDerivativesAfterTask( const unsigned& ider ){
217  unsigned kstart=ider*getNumberOfDerivatives();
218  for(unsigned j=0;j<getNumberOfDerivatives();++j) derivatives[ kstart+j ]=0.0;
219 }
220 
222  bool keep=false;
223  for(unsigned j=0;j<functions.size();++j){
224  // Calculate returns a bool that tells us if this particular
225  // quantity is contributing more than the tolerance
226  if( functions[j]->calculate() ) keep=true;
227  }
228  clearAfterTask();
229  return keep;
230 }
231 
233  // MPI Gather everything
234  if(!serial && buffer.size()>0) comm.Sum( &buffer[0],buffer.size() );
235 
236  // Set the final value of the function
237  for(unsigned j=0;j<functions.size();++j) functions[j]->finish();
238 }
239 
240 void ActionWithVessel::chainRuleForElementDerivatives( const unsigned& iout, const unsigned& ider, const double& df, Vessel* valout ){
242  current_buffer_start=valout->bufstart + (getNumberOfDerivatives()+1)*iout + 1;
243  mergeDerivatives( ider, df );
244 }
245 
246 void ActionWithVessel::chainRuleForElementDerivatives( const unsigned& iout, const unsigned& ider, const unsigned& stride,
247  const unsigned& off, const double& df, Vessel* valout ){
248  plumed_dbg_assert( off<stride );
249  current_buffer_stride=stride;
250  current_buffer_start=valout->bufstart + stride*(getNumberOfDerivatives()+1)*iout + stride + off;
251  mergeDerivatives( ider, df );
252 }
253 
254 void ActionWithVessel::mergeDerivatives( const unsigned& ider, const double& df ){
255  unsigned nder=getNumberOfDerivatives(), vstart=nder*ider;
256  for(unsigned i=0;i<getNumberOfDerivatives();++i){
257  accumulateDerivative( i, df*derivatives[vstart+i] );
258  }
259 }
260 
261 bool ActionWithVessel::getForcesFromVessels( std::vector<double>& forcesToApply ){
262  plumed_dbg_assert( forcesToApply.size()==getNumberOfDerivatives() );
263  forcesToApply.assign( forcesToApply.size(),0.0 );
264  bool wasforced=false;
265  for(int i=0;i<getNumberOfVessels();++i){
266  if( (functions[i]->applyForce( tmpforces )) ){
267  wasforced=true;
268  for(unsigned j=0;j<forcesToApply.size();++j) forcesToApply[j]+=tmpforces[j];
269  }
270  }
271  return wasforced;
272 }
273 
274 void ActionWithVessel::retrieveDomain( std::string& min, std::string& max ){
275  plumed_merror("If your function is periodic you need to add a retrieveDomain function so that ActionWithVessel can retrieve the domain");
276 }
277 
278 }
279 }
BridgeVessel * addBridgingVessel(ActionWithVessel *tome)
Add a bridging vessel to the list of vessels.
void setupMPICommunication(Communicator &comm)
Setup MPI communication if things are activated/deactivated on different nodes.
Definition: DynamicList.h:241
bool parseNumbered(const std::string &key, const int no, T &t)
Parse one numbered keyword as generic type.
Definition: Action.h:300
void parseFlag(const std::string &key, bool &t)
Parse one keyword as boolean flag.
Definition: Action.cpp:104
unsigned current
The numerical index of the task we are curently performing.
unsigned current_buffer_start
The buffers we use for mpi summing DistributionFunction objects.
Vessel * create(std::string keyword, const VesselOptions &da)
Create a distribution function of the specified type.
Log & log
Reference to the log stream.
Definition: Action.h:93
const double epsilon
std::vector< Vessel * > functions
Pointers to the functions we are using on each value.
void chainRuleForElementDerivatives(const unsigned &, const unsigned &, const double &, Vessel *)
Merge the derivatives.
std::vector< bool > thisval_wasset
A boolean that makes sure we don't accumulate very wrong derivatives.
void deactivate(const unsigned ii)
Make a particular element inactive.
Definition: DynamicList.h:246
bool read
This is used to ensure that we have properly read the action.
virtual unsigned getNumberOfDerivatives()=0
Get the number of derivatives for final calculated quantity.
static bool convert(const std::string &str, double &t)
Convert a string to a double, reading it.
Definition: Tools.cpp:74
void error(const std::string &msg) const
Crash calculation and print documentation.
Definition: Action.cpp:195
std::vector< double > tmpforces
Tempory storage for forces.
virtual void mergeDerivatives(const unsigned &ider, const double &df)
STL namespace.
void add(const std::string &t, const std::string &k, const std::string &d)
Add a new keyword of type t with name k and description d.
Definition: Keywords.cpp:167
void addVessel(const std::string &name, const std::string &input, const int numlab=0, const std::string thislab="")
Add a vessel to the list of vessels.
Communicator & comm
Definition: Action.h:158
virtual void calculate()=0
Calculate an Action.
double nl_tolerance
Tolerance for quantities being put in neighbor lists.
void runAllTasks()
Calculate the values of all the vessels.
bool getForcesFromVessels(std::vector< double > &forcesToApply)
Retrieve the forces from all the vessels (used in apply)
void readVesselKeywords()
Complete the setup of this object (this routine must be called after construction of ActionWithValue)...
std::vector< double > thisval
The value of the current element in the sum.
void setOutputAction(ActionWithVessel *myOutputAction)
Setup the action we are outputting to.
void parse(const std::string &key, T &t)
Parse one keyword as generic type.
Definition: Action.h:273
This class holds the keywords and their documentation.
Definition: Keywords.h:36
int Get_rank() const
Obtain the rank of the present process.
This class allows you to calculate the vessel in one ActionWithVessel.
Definition: BridgeVessel.h:40
virtual void retrieveDomain(std::string &min, std::string &max)
What are the domains of the base quantities.
void clearAfterTask()
Clear tempory data that is calculated for each task.
This class is used to bring the relevant information to the Action constructor.
Definition: Action.h:41
bool numbered(const std::string &k) const
Check if numbered keywords are allowed for this action.
Definition: Keywords.cpp:217
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
VesselRegister & vesselRegister()
void accumulateDerivative(const unsigned &ider, const double &df)
This is used to accumulate the derivatives when we merge using chainRuleForElementDerivatives.
bool calculateAllVessels()
This loops over all the vessels calculating them and also sets all the element derivatives equal to z...
virtual void prepare()
Prepare an Action for calculation This can be used by Action if they need some special preparation be...
Definition: Action.cpp:191
virtual void deactivate_task()
Activate the jth colvar Deactivate the current task in future loops.
std::string getKeyword(const unsigned i) const
Return the ith keyword.
Definition: Keywords.cpp:234
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
bool style(const std::string &k, const std::string &t) const
Check if the keyword with name k has style t.
Definition: Keywords.cpp:223
virtual void performTask(const unsigned &j)=0
Calculate one of the functions in the distribution.
DynamicList< unsigned > taskList
The list of tasks we have to perform.
This class is used to pass the input to Vessels.
Definition: Vessel.h:53
unsigned getNumberOfVessels() const
Get the number of vessels.
bool exists(const std::string &k) const
Check if there is a keyword with name k.
Definition: Keywords.cpp:239
void int double * da
Definition: Matrix.h:47
virtual void doJobsRequiredBeforeTaskList()
Do any jobs that are required before the task list is undertaken.
unsigned bufstart
The start of this Vessel's buffer in buffer in the underlying ActionWithVessel.
Definition: Vessel.h:89
void checkRead()
Check that readin was fine.
Definition: Vessel.cpp:111
bool serial
Do all calculations in serial.
unsigned fullSize() const
Return the total number of elements in the list.
Definition: DynamicList.h:225
int Get_size() const
Obtain the number of processes.
std::vector< double > derivatives
Vector of derivatives for the object.
virtual void clearDerivativesAfterTask(const unsigned &)
double tolerance
The tolerance on the accumulators.
const Keywords & keywords
Definition: Action.h:161
bool contributorsAreUnlocked
The terms in the series are locked.
void resizeFunctions()
Resize all the functions when the number of derivatives change.
void Sum(T *, int)
Wrapper for MPI_Allreduce with MPI_SUM.
Definition: Communicator.h:124
unsigned getNumberActive() const
Return the number of elements that are currently active.
Definition: DynamicList.h:230
void addFlag(const std::string &k, const bool def, const std::string &d)
Add a falg with name k that is by default on if def is true and off if def is false. d should provide a description of the flag.
Definition: Keywords.cpp:193
void finishComputations()
Finish running all the calculations.
unsigned size() const
Return the number of defined keywords.
Definition: Keywords.cpp:230
This is used to create PLMD::Action objects that are computed by calculating the same function multip...