All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
MultiColvar.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 "MultiColvar.h"
23 #include "core/PlumedMain.h"
24 #include "core/ActionSet.h"
25 #include "core/SetupMolInfo.h"
26 #include "vesselbase/Vessel.h"
27 #include "tools/Pbc.h"
28 #include <vector>
29 #include <string>
30 
31 using namespace std;
32 namespace PLMD{
33 namespace multicolvar{
34 
35 void MultiColvar::registerKeywords( Keywords& keys ){
36  MultiColvarBase::registerKeywords( keys );
37  keys.reserve("numbered","ATOMS","the atoms involved in each of the collective variables you wish to calculate. "
38  "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one CV will be "
39  "calculated for each ATOM keyword you specify (all ATOM keywords should "
40  "define the same number of atoms). The eventual number of quantities calculated by this "
41  "action will depend on what functions of the distribution you choose to calculate.");
42  keys.reset_style("ATOMS","atoms");
43  keys.reserve("atoms-3","SPECIES","this keyword is used for colvars such as coordination number. In that context it specifies that plumed should calculate "
44  "one coordination number for each of the atoms specified. Each of these coordination numbers specifies how many of the "
45  "other specified atoms are within a certain cutoff of the central atom.");
46  keys.reserve("atoms-4","SPECIESA","this keyword is used for colvars such as the coordination number. In that context it species that plumed should calculate "
47  "one coordination number for each of the atoms specified in SPECIESA. Each of these cooordination numbers specifies how many "
48  "of the atoms specifies using SPECIESB is within the specified cutoff");
49  keys.reserve("atoms-4","SPECIESB","this keyword is used for colvars such as the coordination number. It must appear with SPECIESA. For a full explanation see "
50  "the documentation for that keyword");
51  keys.addFlag("VERBOSE",false,"write a more detailed output");
52 }
53 
54 MultiColvar::MultiColvar(const ActionOptions&ao):
55 Action(ao),
56 MultiColvarBase(ao),
57 verbose_output(false)
58 {
59  parseFlag("VERBOSE",verbose_output);
60 }
61 
62 void MultiColvar::addColvar( const std::vector<unsigned>& newatoms ){
63  if( verbose_output ){
64  log.printf(" Colvar %d is calculated from atoms : ", colvar_atoms.size()+1);
65  for(unsigned i=0;i<newatoms.size();++i) log.printf("%d ",all_atoms(newatoms[i]).serial() );
66  log.printf("\n");
67  }
68  MultiColvarBase::addColvar( newatoms );
69 }
70 
71 void MultiColvar::readAtoms( int& natoms ){
72  if( keywords.exists("ATOMS") ) readAtomsLikeKeyword( "ATOMS", natoms );
73  if( keywords.exists("GROUP") ) readGroupsKeyword( natoms );
74  if( keywords.exists("SPECIES") ) readSpeciesKeyword( natoms );
75 
76  if( all_atoms.fullSize()==0 ) error("No atoms have been read in");
77  // Setup the multicolvar base
79 }
80 
81 void MultiColvar::readAtomsLikeKeyword( const std::string & key, int& natoms ){
82  if( all_atoms.fullSize()>0 ) return;
83 
84  std::vector<AtomNumber> t; std::vector<unsigned> newlist;
85  for(int i=1;;++i ){
86  parseAtomList(key, i, t );
87  if( t.empty() ) break;
88 
89  if(!verbose_output){
90  log.printf(" Colvar %d is calculated from atoms : ", i);
91  for(unsigned j=0;j<t.size();++j) log.printf("%d ",t[j].serial() );
92  log.printf("\n");
93  }
94 
95  if( i==1 && natoms<0 ) natoms=t.size();
96  if( t.size()!=natoms ){
97  std::string ss; Tools::convert(i,ss);
98  error(key + ss + " keyword has the wrong number of atoms");
99  }
100  for(unsigned j=0;j<natoms;++j){
101  newlist.push_back( natoms*(i-1)+j );
102  all_atoms.addIndexToList( t[j] );
103  }
104  t.resize(0); addColvar( newlist );
105  newlist.clear();
106  }
107 }
108 
109 void MultiColvar::readGroupsKeyword( int& natoms ){
110  if( all_atoms.fullSize()>0 ) return;
111 
112  if( natoms==2 ){
113  if( !keywords.exists("GROUPA") ) error("use GROUPA and GROUPB keywords as well as GROUP");
114  if( !keywords.exists("GROUPB") ) error("use GROUPA and GROUPB keywords as well as GROUP");
115  } else if( natoms==3 ){
116  if( !keywords.exists("GROUPA") ) error("use GROUPA, GROUPB and GROUPC keywords as well as GROUP");
117  if( !keywords.exists("GROUPB") ) error("use GROUPA, GROUPB and GROUPC keywords as well as GROUP");
118  if( !keywords.exists("GROUPC") ) error("use GROUPA, GROUPB and GROUPC keywords as well as GROUP");
119  } else {
120  error("Cannot use groups keyword unless the number of atoms equals 2 or 3");
121  }
122 
123  std::vector<AtomNumber> t;
124  parseAtomList("GROUP",t);
125  if( !t.empty() ){
126  for(unsigned i=0;i<t.size();++i) all_atoms.addIndexToList( t[i] );
127  std::vector<unsigned> newlist;
128  if(natoms==2){
129  for(unsigned i=1;i<t.size();++i){
130  for(unsigned j=0;j<i;++j){
131  newlist.push_back(i); newlist.push_back(j); addColvar( newlist ); newlist.clear();
132  }
133  }
134  } else if(natoms==3){
135  for(unsigned i=2;i<t.size();++i){
136  for(unsigned j=1;j<i;++j){
137  for(unsigned k=0;k<j;++k){
138  newlist.push_back(i); newlist.push_back(j);
139  newlist.push_back(k); addColvar( newlist );
140  newlist.clear();
141  }
142  }
143  }
144  }
145  if( !verbose_output ){
146  log.printf(" constructing colvars from %d atoms : ", t.size() );
147  for(unsigned i=0;i<t.size();++i) log.printf("%d ",t[i].serial() );
148  log.printf("\n");
149  }
150  } else {
151  if(natoms==2){
152  readTwoGroups("GROUPA","GROUPB");
153  } else if(natoms==3){
154  readThreeGroups("GROUPA","GROUPB","GROUPC",true);
155  } else {
156  plumed_merror("can only use groups for colvars involving 2 or 3 atoms");
157  }
158  }
159 }
160 
161 void MultiColvar::readTwoGroups( const std::string& key1, const std::string& key2 ){
162  plumed_assert( all_atoms.fullSize()==0 );
163 
164  std::vector<AtomNumber> t1, t2; std::vector<unsigned> newlist;
165  parseAtomList(key1,t1); parseAtomList(key2,t2);
166  if( t1.empty() ) error("missing atom specification " + key1);
167  if ( t2.empty() ) error("missing atom specification " + key2);
168  for(unsigned i=0;i<t1.size();++i) all_atoms.addIndexToList( t1[i] );
169  for(unsigned i=0;i<t2.size();++i) all_atoms.addIndexToList( t2[i] );
170  for(unsigned i=0;i<t1.size();++i){
171  for(unsigned j=0;j<t2.size();++j){
172  newlist.push_back(i); newlist.push_back( t1.size() + j ); addColvar( newlist ); newlist.clear();
173  }
174  }
175  if( !verbose_output ){
176  log.printf(" constructing colvars from two groups containing %d and %d atoms respectively\n",t1.size(),t2.size() );
177  log.printf(" group %s contains atoms : ", key1.c_str() );
178  for(unsigned i=0;i<t1.size();++i) log.printf("%d ",t1[i].serial() );
179  log.printf("\n");
180  log.printf(" group %s contains atoms : ", key2.c_str() );
181  for(unsigned i=0;i<t2.size();++i) log.printf("%d ",t2[i].serial() );
182  log.printf("\n");
183  }
184 }
185 
186 void MultiColvar::readThreeGroups( const std::string& key1, const std::string& key2, const std::string& key3, const bool& allow2 ){
187  plumed_assert( all_atoms.fullSize()==0 );
188 
189  std::vector<AtomNumber> t1, t2, t3; std::vector<unsigned> newlist;
190  parseAtomList(key1,t1); parseAtomList(key2,t2);
191  if( t1.empty() ) error("missing atom specification " + key1);
192  if( t2.empty() ) error("missing atom specification " + key2);
193  for(unsigned i=0;i<t1.size();++i) all_atoms.addIndexToList( t1[i] );
194  for(unsigned i=0;i<t2.size();++i) all_atoms.addIndexToList( t2[i] );
195  parseAtomList(key3,t3);
196  if( t3.empty() && !allow2 ){
197  error("missing atom specification " + key3);
198  } else if( t3.empty() ){
199  for(unsigned i=0;i<t1.size();++i){
200  for(unsigned j=1;j<t2.size();++j){
201  for(unsigned k=0;k<j;++k){
202  newlist.push_back( t1.size() + j );
203  newlist.push_back(i);
204  newlist.push_back( t1.size() + k );
205  addColvar( newlist ); newlist.clear();
206  }
207  }
208  }
209  if( !verbose_output ){
210  log.printf(" constructing colvars from two groups containing %d and %d atoms respectively\n",t1.size(),t2.size() );
211  log.printf(" group %s contains atoms : ", key1.c_str() );
212  for(unsigned i=0;i<t1.size();++i) log.printf("%d ",t1[i].serial() );
213  log.printf("\n");
214  log.printf(" group %s contains atoms : ", key2.c_str() );
215  for(unsigned i=0;i<t2.size();++i) log.printf("%d ",t2[i].serial() );
216  log.printf("\n");
217  }
218  } else {
219  for(unsigned i=0;i<t3.size();++i) all_atoms.addIndexToList( t3[i] );
220  for(unsigned i=0;i<t1.size();++i){
221  for(unsigned j=0;j<t2.size();++j){
222  for(unsigned k=0;k<t3.size();++k){
223  newlist.push_back( t1.size() + j );
224  newlist.push_back(i);
225  newlist.push_back( t1.size() + t2.size() + k );
226  addColvar( newlist ); newlist.clear();
227  }
228  }
229  }
230  if( !verbose_output ){
231  log.printf(" constructing colvars from three groups containing %d, %d and %d atoms respectively\n",t1.size(),t2.size(),t3.size() );
232  log.printf(" group %s contains atoms : ", key1.c_str() );
233  for(unsigned i=0;i<t1.size();++i) log.printf("%d ",t1[i].serial() );
234  log.printf("\n");
235  log.printf(" group %s contains atoms : ", key2.c_str() );
236  for(unsigned i=0;i<t2.size();++i) log.printf("%d ",t2[i].serial() );
237  log.printf("\n");
238  log.printf(" group %s contains atoms : ", key3.c_str() );
239  for(unsigned i=0;i<t3.size();++i) log.printf("%d ",t3[i].serial() );
240  log.printf("\n");
241  }
242  }
243 }
244 
246  if( all_atoms.fullSize()>0 ) return ;
247 
248  std::vector<AtomNumber> t;
249  parseAtomList("SPECIES",t);
250  if( !t.empty() ){
251  natoms=t.size();
252  for(unsigned i=0;i<t.size();++i) all_atoms.addIndexToList( t[i] );
253  std::vector<unsigned> newlist;
254  if( keywords.exists("SPECIESA") && keywords.exists("SPECIESB") ){
255  for(unsigned i=0;i<t.size();++i){
256  newlist.push_back(i);
257  for(unsigned j=0;j<t.size();++j){
258  if(i!=j) newlist.push_back(j);
259  }
260  addColvar( newlist ); newlist.clear();
261  }
262  if( !verbose_output ){
263  log.printf(" generating colvars from %d atoms of a particular type\n",t.size() );
264  log.printf(" atoms involved : ");
265  for(unsigned i=0;i<t.size();++i) log.printf("%d ",t[i].serial() );
266  log.printf("\n");
267  }
268  } else if( !( keywords.exists("SPECIESA") && keywords.exists("SPECIESB") ) ){
269  std::vector<unsigned> newlist; verbose_output=false; // Make sure we don't do verbose output
270  log.printf(" involving atoms : ");
271  for(unsigned i=0;i<t.size();++i){
272  newlist.push_back(i); addColvar( newlist ); newlist.clear();
273  log.printf(" %d",t[i].serial() );
274  }
275  log.printf("\n");
276  } else {
277  plumed_merror("SPECIES keyword is not for density or coordination like CV");
278  }
279  } else if( keywords.exists("SPECIESA") && keywords.exists("SPECIESB") ) {
280  std::vector<AtomNumber> t1,t2;
281  parseAtomList("SPECIESA",t1);
282  if( !t1.empty() ){
283  parseAtomList("SPECIESB",t2);
284  if ( t2.empty() ) error("SPECIESB keyword defines no atoms or is missing. Use either SPECIESA and SPECIESB or just SPECIES");
285  natoms=1+t2.size();
286  for(unsigned i=0;i<t1.size();++i) all_atoms.addIndexToList( t1[i] );
287  for(unsigned i=0;i<t2.size();++i) all_atoms.addIndexToList( t2[i] );
288  std::vector<unsigned> newlist;
289  for(unsigned i=0;i<t1.size();++i){
290  newlist.push_back(i);
291  for(unsigned j=0;j<t2.size();++j){
292  if( t1[i]!=t2[j] ) newlist.push_back( t1.size() + j );
293  }
294  addColvar( newlist ); newlist.clear();
295  }
296  if( !verbose_output ){
297  log.printf(" generating colvars from a group of %d central atoms and %d other atoms\n",t1.size(), t2.size() );
298  log.printf(" central atoms are : ");
299  for(unsigned i=0;i<t1.size();++i) log.printf("%d ",t1[i].serial() );
300  log.printf("\n");
301  log.printf(" other atoms are : ");
302  for(unsigned i=0;i<t2.size();++i) log.printf("%d ",t2[i].serial() );
303  log.printf("\n");
304  }
305  }
306  }
307 }
308 
310  for(unsigned i=0;i<taskList.getNumberActive();++i){
311  unsigned n=taskList[i];
312  for(unsigned j=0;j<colvar_atoms[n].getNumberActive();++j){
313  all_atoms.activate( colvar_atoms[n][j] );
314  }
315  }
316  all_atoms.updateActiveMembers();
317  // Request the atoms
318  ActionAtomistic::requestAtoms( all_atoms.retrieveActiveList() );
319 }
320 
322  runAllTasks();
323 }
324 
325 double MultiColvar::doCalculation( const unsigned& j ){
326  double val=compute(j);
328  for(unsigned i=0;i<getNAtoms();++i) atoms_with_derivatives.updateIndex( getAtomIndex(i) );
330  return val;
331 }
332 
334  Vector catom=getCentralAtom();
336  for(unsigned i=0;i<getNAtoms();++i) atomsWithCatomDer.updateIndex( getAtomIndex(i) );
338  return catom;
339 }
340 
341 }
342 }
void parseFlag(const std::string &key, bool &t)
Parse one keyword as boolean flag.
Definition: Action.cpp:104
Log & log
Reference to the log stream.
Definition: Action.h:93
void readAtoms(int &natoms)
Read in all the keywords that can be used to define atoms.
Definition: MultiColvar.cpp:71
unsigned getNAtoms() const
Get the number of atoms in this particular colvar.
void readAtomsLikeKeyword(const std::string &key, int &natoms)
Read in ATOMS keyword.
Definition: MultiColvar.cpp:81
Class implementing fixed size vectors of doubles.
Definition: Vector.h:74
void addColvar(const std::vector< unsigned > &newatoms)
Add a collective variable.
Definition: MultiColvar.cpp:62
void resizeDynamicArrays()
Resize all the dynamic arrays (used at neighbor list update time and during setup) ...
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
double doCalculation(const unsigned &j)
Do the calculation.
STL namespace.
void parseAtomList(const std::string &key, std::vector< AtomNumber > &t)
Parse a list of atoms without a numbered keyword.
void addColvar(const std::vector< unsigned > &newatoms)
Add a colvar to the set of colvars we are calculating (in practise just a list of atoms) ...
void sortActiveList()
This sorts the elements in the active list.
Definition: DynamicList.h:306
unsigned getAtomIndex(const unsigned &) const
Return the index of an atom.
void runAllTasks()
Calculate the values of all the vessels.
void setupMultiColvarBase()
Finish setting up the multicolvar base.
void const char const char int * n
Definition: Matrix.h:42
virtual double compute(const unsigned &j)=0
Actually compute the colvar.
void updateIndex(const unsigned &ii)
This can be used for a fast version of updateActiveMembers in which only a subset of the indexes are ...
Definition: DynamicList.h:299
DynamicList< unsigned > atomsWithCatomDer
This class holds the keywords and their documentation.
Definition: Keywords.h:36
virtual Vector getCentralAtom()=0
Get the position of the central atom.
void emptyActiveMembers()
Empty the list of active members.
Definition: DynamicList.h:294
std::vector< DynamicList< unsigned > > colvar_atoms
The lists of the atoms involved in each of the individual colvars note these refer to the atoms in al...
This class is used to bring the relevant information to the Action constructor.
Definition: Action.h:41
void readTwoGroups(const std::string &key1, const std::string &key2)
Read two group keywords.
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
bool verbose_output
Have atoms been read in.
Definition: MultiColvar.h:42
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
DynamicList< unsigned > taskList
The list of tasks we have to perform.
bool exists(const std::string &k) const
Check if there is a keyword with name k.
Definition: Keywords.cpp:239
Vector calculateCentralAtomPosition()
Calculate the position of the central atom.
void readThreeGroups(const std::string &key1, const std::string &key2, const std::string &key3, const bool &allow2)
Read three groups.
void requestAtoms(const std::vector< AtomNumber > &a)
Request an array of atoms.
DynamicList< unsigned > atoms_with_derivatives
A dynamic list containing those atoms with derivatives.
DynamicList< AtomNumber > all_atoms
The list of all the atoms involved in the colvar.
void readGroupsKeyword(int &natoms)
Read in the various GROUP keywords.
void readSpeciesKeyword(int &natoms)
Read in the various SPECIES keywords.
bool serial
Do all calculations in serial.
void reset_style(const std::string &k, const std::string &style)
Change the style of a keyword.
Definition: Keywords.cpp:161
const Keywords & keywords
Definition: Action.h:161
virtual void calculate()
Calculate the multicolvar.
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