1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2    Copyright (c) 2012-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_vesselbase_Vessel_h
23 #define __PLUMED_vesselbase_Vessel_h
24 
25 #include <string>
26 #include <cstring>
27 #include <vector>
28 #include <algorithm>
29 #include "tools/Exception.h"
30 #include "tools/Keywords.h"
31 #include "ActionWithVessel.h"
32 
33 namespace PLMD {
34 
35 class Communicator;
36 class Log;
37 
38 namespace vesselbase {
39 
40 /**
41 \ingroup TOOLBOX
42 Vessels are an important component of class PLMD::ActionWithVessel.  This class
43 contains a large buffer array of doubles.  The various elements of this array
44 can be accessed through vessels which are used to structure the elements of the
45 double array.  As the buffer array is just a vector of doubles it can be easily
46 mpi gathered or passed to another node.
47 */
48 
49 //class ActionWithVessel;
50 class Vessel;
51 
52 /// This class is used to pass the input to Vessels
53 class VesselOptions {
54   friend class Vessel;
55 private:
56 /// The name of the particular vessel
57   std::string myname;
58 /// The label for this particular vessel;
59   std::string mylabel;
60 /// The numerical label for this vessel
61   int numlab;
62 /// Pointer to ActionWithVessel that this if from
63   ActionWithVessel* action;
64 /// The keywords
65   const Keywords& keywords;
66   static Keywords emptyKeys;
67 public:
68 /// The parameters that are read into the function
69   std::string parameters;
70 /// The constructor
71   VesselOptions( const std::string& thisname, const std::string& thislab, const unsigned& nlab, const std::string& params, ActionWithVessel* aa );
72   VesselOptions(const VesselOptions& da, const Keywords& keys );
73 };
74 
75 class Vessel {
76   friend class ActionWithVessel;
77 private:
78 /// The keyword for the vessel in the input file
79   std::string myname;
80 /// The label for the vessel for referencing
81   std::string mylabel;
82 /// The numerical label for this object
83   const int numlab;
84 /// The action that this vessel is created within
85   ActionWithVessel* action;
86 /// The number of elements in this vessel's buffered data
87   unsigned bufsize;
88 /// Directive line.
89 /// This line is progressively erased during vessel construction
90 /// so as to check if all the present keywords are correct.
91   std::vector<std::string> line;
92 /// The keywords
93   const PLMD::Keywords& keywords;
94 /// This just checks we have done checkRead
95   bool finished_read;
96 protected:
97 /// The start of this Vessel's buffer in buffer in the underlying ActionWithVessel
98   unsigned bufstart;
99 /// Return the numerical label
100   int getNumericalLabel() const ;
101 /// Report an error
102   void error(const std::string& errmsg);
103 /// Parse something from the input
104   template<class T>
105   void parse(const std::string&key, T&t);
106 /// Parse one keyword as std::vector
107   template<class T>
108   void parseVector(const std::string&key,std::vector<T>&t);
109 /// Parse one keyword as boolean flag
110   void parseFlag(const std::string&key,bool&t);
111 /// This returns the whole input line (it is used for less_than/more_than/between)
112   std::string getAllInput();
113 /// Return a pointer to the action we are working in
114   ActionWithVessel* getAction() const ;
115 /// Return the value of the tolerance
116   double getTolerance() const ;
117 /// Return the value of the neighbor list tolerance
118   double getNLTolerance() const ;
119 /// Return the size of the buffer
120   unsigned getSizeOfBuffer() const ;
121 /// Set the size of the data buffer
122   void resizeBuffer( const unsigned& n );
123 public:
124 /// Reserve any keywords for this particular vessel
125   static void registerKeywords( Keywords& keys );
126 /// Convert the name to the label of the component
127   static std::string transformName( const std::string& name );
128 /// The constructor
129   explicit Vessel( const VesselOptions& da );
130 /// Virtual destructor needed for proper inheritance
~Vessel()131   virtual ~Vessel() {}
132 /// Return the name
133   std::string getName() const ;
134 /// Return the label
135   std::string getLabel() const ;
136 /// Check that readin was fine
137   void checkRead();
138 /// Return a description of the vessel contents
139   virtual std::string description()=0;
140 /// Set the start of the buffer
141   virtual void setBufferStart( unsigned& start );
142 /// Do something before the loop
prepare()143   virtual void prepare() {}
144 /// This is replaced in bridges so we can transform the derivatives
145   virtual MultiValue& transformDerivatives( const unsigned& current, MultiValue& myvals, MultiValue& bvals );
146 /// Calculate the part of the vessel that is done in the loop
147   virtual void calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer, std::vector<unsigned>& der_list ) const = 0;
148 /// Complete the calculation once the loop is finished
149   virtual void finish( const std::vector<double>& )=0;
150 /// Reset the size of the buffers
151   virtual void resize()=0;
152 /// Retrieve the forces on the quantities in the vessel
153   virtual bool applyForce( std::vector<double>& forces )=0;
154 };
155 
156 template<class T>
parse(const std::string & key,T & t)157 void Vessel::parse(const std::string&key, T&t ) {
158   plumed_massert(keywords.exists(key),"keyword " + key + " has not been registered");
159 
160   // Now try to read the keyword
161   bool found=Tools::parse(line,key,t); std::string def;
162   if ( !found && keywords.style(key,"compulsory") ) {
163     if( keywords.getDefaultValue(key,def) ) {
164       plumed_massert( def.length()!=0 && Tools::convert(def,t), "default value is dubious");
165     } else {
166       error("keyword " + key + " is comulsory for this vessel");
167     }
168   }
169 }
170 
171 template<class T>
parseVector(const std::string & key,std::vector<T> & t)172 void Vessel::parseVector(const std::string&key,std::vector<T>&t) {
173   // Check keyword has been registered
174   plumed_massert(keywords.exists(key), "keyword " + key + " has not been registered");
175   unsigned size=t.size(); bool skipcheck=false;
176   if(size==0) skipcheck=true;
177 
178   // Now try to read the keyword
179   bool found; std::string def; T val;
180   found=Tools::parseVector(line,key,t);
181 
182   // Check vectors size is correct (not if this is atoms or ARG)
183   if( !keywords.style(key,"atoms") && found ) {
184     if( !skipcheck && t.size()!=size ) error("vector read in for keyword " + key + " has the wrong size");
185   }
186 
187   // If it isn't read and it is compulsory see if a default value was specified
188   if ( !found && keywords.style(key,"compulsory") ) {
189     if( keywords.getDefaultValue(key,def) ) {
190       if( def.length()==0 || !Tools::convert(def,val) ) {
191         plumed_merror("weird default value for keyword " + key );
192       } else {
193         for(unsigned i=0; i<t.size(); ++i) t[i]=val;
194       }
195     } else {
196       error("keyword " + key + " is compulsory");
197     }
198   } else if ( !found ) {
199     t.resize(0);
200   }
201 }
202 
203 inline
getNumericalLabel()204 int Vessel::getNumericalLabel() const {
205   return numlab;
206 }
207 
208 inline
setBufferStart(unsigned & start)209 void Vessel::setBufferStart( unsigned& start ) {
210   bufstart=start; start+=bufsize;
211 }
212 
213 inline
transformDerivatives(const unsigned & current,MultiValue & myvals,MultiValue & bvals)214 MultiValue& Vessel::transformDerivatives( const unsigned& current, MultiValue& myvals, MultiValue& bvals ) {
215   return myvals;
216 }
217 
218 inline
resizeBuffer(const unsigned & n)219 void Vessel::resizeBuffer( const unsigned& n ) {
220   bufsize=n;
221 }
222 
223 inline
getTolerance()224 double Vessel::getTolerance() const {
225   return action->tolerance;
226 }
227 
228 inline
getNLTolerance()229 double Vessel::getNLTolerance() const {
230   return action->nl_tolerance;
231 }
232 
233 inline
getAction()234 ActionWithVessel* Vessel::getAction() const {
235   return action;
236 }
237 
238 inline
getSizeOfBuffer()239 unsigned Vessel::getSizeOfBuffer() const {
240   return bufsize;
241 }
242 
243 }
244 }
245 #endif
246