All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Atoms.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 "Atoms.h"
23 #include "ActionAtomistic.h"
24 #include "MDAtoms.h"
25 #include "PlumedMain.h"
26 #include "tools/Pbc.h"
27 #include <algorithm>
28 #include <iostream>
29 #include <string>
30 
31 using namespace std;
32 
33 namespace PLMD {
34 
35 class PlumedMain;
36 
37 Atoms::Atoms(PlumedMain&plumed):
38  natoms(0),
39  pbc(*new Pbc),
40  energy(0.0),
41  dataCanBeSet(false),
42  collectEnergy(0.0),
43  energyHasBeenSet(false),
44  positionsHaveBeenSet(0),
45  massesHaveBeenSet(false),
46  chargesHaveBeenSet(false),
47  boxHasBeenSet(false),
48  forcesHaveBeenSet(0),
49  virialHasBeenSet(false),
50  plumed(plumed),
51  naturalUnits(false),
52  timestep(0.0),
53  forceOnEnergy(0.0)
54 {
55  mdatoms=MDAtomsBase::create(sizeof(double));
56 }
57 
59  if(actions.size()>0){
60  std::cerr<<"WARNING: there is some inconsistency in action added to atoms, as some of them were not properly destroyed. This might indicate an internal bug!!\n";
61  }
62  delete mdatoms;
63  delete &pbc;
64 }
65 
70 }
71 
72 void Atoms::setBox(void*p){
73  mdatoms->setBox(p);
74  Tensor b; mdatoms->getBox(b); boxHasBeenSet=true;
75 }
76 
77 void Atoms::setPositions(void*p){
78  plumed_massert( dataCanBeSet ,"setPositions must be called after setStep in MD code interface");
79  plumed_massert( p || gatindex.size()==0, "NULL position pointer with non-zero local atoms");
81 }
82 
83 void Atoms::setMasses(void*p){
84  plumed_massert( dataCanBeSet ,"setMasses must be called after setStep in MD code interface");
85  plumed_massert( p || gatindex.size()==0, "NULL mass pointer with non-zero local atoms");
86  mdatoms->setm(p); massesHaveBeenSet=true;
87 
88 }
89 
90 void Atoms::setCharges(void*p){
91  plumed_massert( dataCanBeSet, "setCharges must be called after setStep in MD code interface");
92  plumed_massert( p || gatindex.size()==0, "NULL charges pointer with non-zero local atoms");
94 }
95 
96 void Atoms::setVirial(void*p){
97  plumed_massert( dataCanBeSet ,"setVirial must be called after setStep in MD code interface");
99 
100 }
101 
102 void Atoms::setEnergy(void*p){
103  plumed_massert( dataCanBeSet ,"setEnergy must be called after setStep in MD code interface");
104  MD2double(p,md_energy);
106  energyHasBeenSet=true;
107 }
108 
109 void Atoms::setForces(void*p){
110  plumed_massert( dataCanBeSet ,"setForces must be called after setStep in MD code interface");
111  plumed_massert( p || gatindex.size()==0, "NULL force pointer with non-zero local atoms");
113  mdatoms->setf(p);
114 }
115 
116 void Atoms::setPositions(void*p,int i){
117  plumed_massert( dataCanBeSet ,"setPositions must be called after setStep in MD code interface");
118  plumed_massert( p || gatindex.size()==0, "NULL positions pointer with non-zero local atoms");
120 }
121 
122 void Atoms::setForces(void*p,int i){
123  plumed_massert( dataCanBeSet ,"setForces must be called after setStep in MD code interface");
124  plumed_massert( p || gatindex.size()==0, "NULL force pointer with non-zero local atoms");
125  mdatoms->setf(p,i); forcesHaveBeenSet++;
126 }
127 
129  std::set<AtomNumber> unique;
130  if(dd && int(gatindex.size())<natoms){
131  for(unsigned i=0;i<actions.size();i++) if(actions[i]->isActive()) {
132  unique.insert(actions[i]->getUnique().begin(),actions[i]->getUnique().end());
133  }
134  }
135  share(unique);
136 }
137 
139  std::set<AtomNumber> unique;
140  if(dd && int(gatindex.size())<natoms)
141  for(int i=0;i<natoms;i++) unique.insert(AtomNumber::index(i));
142  share(unique);
143 }
144 
145 void Atoms::share(const std::set<AtomNumber>& unique){
146  plumed_assert( positionsHaveBeenSet==3 && massesHaveBeenSet );
147  mdatoms->getBox(box);
151  if(dd && int(gatindex.size())<natoms){
152  if(dd.async){
153  for(unsigned i=0;i<dd.mpi_request_positions.size();i++) dd.mpi_request_positions[i].wait();
154  for(unsigned i=0;i<dd.mpi_request_index.size();i++) dd.mpi_request_index[i].wait();
155  }
156  int count=0;
157  for(std::set<AtomNumber>::const_iterator p=unique.begin();p!=unique.end();++p){
158  if(dd.g2l[p->index()]>=0){
159  dd.indexToBeSent[count]=p->index();
160  dd.positionsToBeSent[5*count+0]=positions[p->index()][0];
161  dd.positionsToBeSent[5*count+1]=positions[p->index()][1];
162  dd.positionsToBeSent[5*count+2]=positions[p->index()][2];
163  dd.positionsToBeSent[5*count+3]=masses[p->index()];
164  dd.positionsToBeSent[5*count+4]=charges[p->index()];
165  count++;
166  }
167  }
168  if(dd.async){
170  dd.mpi_request_index.resize(dd.Get_size());
171  for(int i=0;i<dd.Get_size();i++){
172  dd.mpi_request_index[i]=dd.Isend(&dd.indexToBeSent[0],count,i,666);
173  dd.mpi_request_positions[i]=dd.Isend(&dd.positionsToBeSent[0],5*count,i,667);
174  }
175  }else{
176  const int n=(dd.Get_size());
177  vector<int> counts(n);
178  vector<int> displ(n);
179  vector<int> counts5(n);
180  vector<int> displ5(n);
181  dd.Allgather(&count,1,&counts[0],1);
182  displ[0]=0;
183  for(int i=1;i<n;++i) displ[i]=displ[i-1]+counts[i-1];
184  for(int i=0;i<n;++i) counts5[i]=counts[i]*5;
185  for(int i=0;i<n;++i) displ5[i]=displ[i]*5;
186  dd.Allgatherv(&dd.indexToBeSent[0],count,&dd.indexToBeReceived[0],&counts[0],&displ[0]);
187  dd.Allgatherv(&dd.positionsToBeSent[0],5*count,&dd.positionsToBeReceived[0],&counts5[0],&displ5[0]);
188  int tot=displ[n-1]+counts[n-1];
189  for(int i=0;i<tot;i++){
195  }
196  }
197  }
198  virial.zero();
199  for(unsigned i=0;i<gatindex.size();i++) forces[gatindex[i]].zero();
200  for(unsigned i=getNatoms();i<positions.size();i++) forces[i].zero(); // virtual atoms
201  forceOnEnergy=0.0;
202 }
203 
204 void Atoms::wait(){
205  dataCanBeSet=false; // Everything should be set by this stage
206 
207  if(dd){
208  dd.Bcast(&box[0][0],9,0);
209  }
210  pbc.setBox(box);
211 
213 
214  if(dd && int(gatindex.size())<natoms){
215 // receive toBeReceived
216  Communicator::Status status;
217  if(dd.async){
218  int count=0;
219  for(int i=0;i<dd.Get_size();i++){
220  dd.Recv(&dd.indexToBeReceived[count],dd.indexToBeReceived.size()-count,i,666,status);
221  int c=status.Get_count<int>();
222  dd.Recv(&dd.positionsToBeReceived[5*count],dd.positionsToBeReceived.size()-5*count,i,667);
223  count+=c;
224  }
225  for(int i=0;i<count;i++){
231  }
232  }
233  if(collectEnergy) dd.Sum(&energy,1);
234  }
235 }
236 
238  plumed_assert( forcesHaveBeenSet==3 );
240  double alpha=1.0-forceOnEnergy;
242  }
244  if( !plumed.novirial && dd.Get_rank()==0 ){
245  plumed_assert( virialHasBeenSet );
247  }
248 }
249 
250 void Atoms::setNatoms(int n){
251  natoms=n;
252  positions.resize(n);
253  forces.resize(n);
254  masses.resize(n);
255  charges.resize(n);
256  gatindex.resize(n);
257  for(unsigned i=0;i<gatindex.size();i++) gatindex[i]=i;
258 }
259 
260 
262  actions.push_back(a);
263 }
264 
266  vector<const ActionAtomistic*>::iterator f=find(actions.begin(),actions.end(),a);
267  plumed_massert(f!=actions.end(),"cannot remove an action registered to atoms");
268  actions.erase(f);
269 }
270 
271 
273  on=true;
274  Set_comm(c.Get_comm());
275  async=Get_size()<10;
276 }
277 
279  gatindex.resize(n);
280  if(dd){
281  dd.g2l.resize(natoms,-1);
282  dd.positionsToBeSent.resize(n*5,0.0);
283  dd.positionsToBeReceived.resize(natoms*5,0.0);
284  dd.indexToBeSent.resize(n,0);
285  dd.indexToBeReceived.resize(natoms,0);
286  };
287 }
288 
290  plumed_massert( g || gatindex.size()==0, "NULL gatindex pointer with non-zero local atoms");
291  for(unsigned i=0;i<gatindex.size();i++) gatindex[i]=g[i];
292  for(unsigned i=0;i<dd.g2l.size();i++) dd.g2l[i]=-1;
293  if(dd) for(unsigned i=0;i<gatindex.size();i++) dd.g2l[gatindex[i]]=i;
294 }
295 
297  for(unsigned i=0;i<gatindex.size();i++) gatindex[i]=start+i;
298  for(unsigned i=0;i<dd.g2l.size();i++) dd.g2l[i]=-1;
299  if(dd) for(unsigned i=0;i<gatindex.size();i++) dd.g2l[gatindex[i]]=i;
300 }
301 
303  delete mdatoms;
305 }
306 
308  return mdatoms->getRealPrecision();
309 }
310 
311 void Atoms::MD2double(const void*m,double&d)const{
312  plumed_assert(mdatoms); mdatoms->MD2double(m,d);
313 }
314 void Atoms::double2MD(const double&d,void*m)const{
315  plumed_assert(mdatoms); mdatoms->double2MD(d,m);
316 }
317 
320 }
321 
322 void Atoms::setTimeStep(void*p){
323  MD2double(p,timestep);
324 }
325 
326 double Atoms::getTimeStep()const{
327  return timestep/units.getTime()*MDUnits.getTime();
328 }
329 
331  vector<AtomNumber> fullListTmp;
332  for(unsigned i=0;i<actions.size();i++) if(actions[i]->isActive())
333  fullListTmp.insert(fullListTmp.end(),actions[i]->getUnique().begin(),actions[i]->getUnique().end());
334  std::sort(fullListTmp.begin(),fullListTmp.end());
335  int nn=std::unique(fullListTmp.begin(),fullListTmp.end())-fullListTmp.begin();
336  fullList.resize(nn);
337  for(unsigned i=0;i<nn;++i) fullList[i]=fullListTmp[i].index();
338  *n=nn;
339 }
340 
341 void Atoms::getFullList(int**x){
342  if(!fullList.empty()) *x=&fullList[0];
343  else *x=NULL;
344 }
345 
347  fullList.resize(0);
348 }
349 
350 void Atoms::init(){
351 // Default: set domain decomposition to NO-decomposition, waiting for
352 // further instruction
353  if(dd){
356  }
357 }
358 
360  dd.enable(comm);
361 }
362 
363 void Atoms::resizeVectors(unsigned n){
364  positions.resize(n);
365  forces.resize(n);
366  masses.resize(n);
367  charges.resize(n);
368 }
369 
371  unsigned n=positions.size();
372  resizeVectors(n+1);
373  virtualAtomsActions.push_back(a);
374  return AtomNumber::index(n);
375 }
376 
378  unsigned n=positions.size();
379  plumed_massert(a==virtualAtomsActions[virtualAtomsActions.size()-1],"virtual atoms should be destroyed in reverse creation order");
380  resizeVectors(n-1);
381  virtualAtomsActions.pop_back();
382 }
383 
384 void Atoms::insertGroup(const std::string&name,const std::vector<AtomNumber>&a){
385  plumed_massert(groups.count(name)==0,"group named "+name+" already exists");
386  groups[name]=a;
387 }
388 
389 void Atoms::removeGroup(const std::string&name){
390  plumed_massert(groups.count(name)==1,"cannot remove group named "+name);
391  groups.erase(name);
392 }
393 
394 void Atoms::writeBinary(std::ostream&o)const{
395  o.write(reinterpret_cast<const char*>(&positions[0][0]),natoms*3*sizeof(double));
396  o.write(reinterpret_cast<const char*>(&box(0,0)),9*sizeof(double));
397  o.write(reinterpret_cast<const char*>(&energy),sizeof(double));
398 }
399 
400 void Atoms::readBinary(std::istream&i){
401  i.read(reinterpret_cast<char*>(&positions[0][0]),natoms*3*sizeof(double));
402  i.read(reinterpret_cast<char*>(&box(0,0)),9*sizeof(double));
403  i.read(reinterpret_cast<char*>(&energy),sizeof(double));
404  pbc.setBox(box);
405 }
406 
407 double Atoms::getKBoltzmann()const{
408  if(naturalUnits) return 1.0;
409  else return kBoltzmann/units.getEnergy();
410 }
411 
413  if(naturalUnits) return 1.0;
414  else return kBoltzmann/MDUnits.getEnergy();
415 }
416 
417 }
418 
419 
double forceOnEnergy
Definition: Atoms.h:90
std::vector< const ActionAtomistic * > actions
Definition: Atoms.h:92
void zero()
set it to zero
Definition: Tensor.h:198
void wait()
Definition: Atoms.cpp:204
Simple class to store the index of an atom.
Definition: AtomNumber.h:39
const int & getNatoms() const
Definition: Atoms.h:201
virtual void setf(void *f)=0
Set a pointer to the forces array in the MD code.
void removeVirtualAtom(ActionWithVirtualAtom *)
Definition: Atoms.cpp:377
std::vector< int > g2l
Definition: Atoms.h:101
void setVirial(void *)
Definition: Atoms.cpp:96
void getFullList(int **)
Definition: Atoms.cpp:341
AtomNumber addVirtualAtom(ActionWithVirtualAtom *)
Definition: Atoms.cpp:370
std::vector< Vector > forces
Definition: Atoms.h:51
std::vector< double > charges
Definition: Atoms.h:53
virtual unsigned getRealPrecision() const =0
Get the size of MD-real.
double getMDKBoltzmann() const
Definition: Atoms.cpp:412
const double epsilon
void setTimeStep(void *)
Definition: Atoms.cpp:322
bool massesHaveBeenSet
Definition: Atoms.h:67
void removeGroup(const std::string &name)
Definition: Atoms.cpp:389
void setCharges(void *)
Definition: Atoms.cpp:90
void setAtomsContiguous(int)
Definition: Atoms.cpp:296
bool virialHasBeenSet
Definition: Atoms.h:71
Class implementing fixed size matrices of doubles.
Definition: Tensor.h:70
void add(const ActionAtomistic *)
Definition: Atoms.cpp:261
virtual void getMasses(const std::vector< int > &index, std::vector< double > &m) const =0
Retrieve selected masses.
void enable(Communicator &c)
Definition: Atoms.cpp:272
void updateForces()
Definition: Atoms.cpp:237
int getRealPrecision() const
Definition: Atoms.cpp:307
void Bcast(T *, int, int)
Definition: Communicator.h:134
std::vector< double > masses
Definition: Atoms.h:52
MPI_Comm & Get_comm()
Reference to MPI communicator.
void setAtomsNlocal(int)
Definition: Atoms.cpp:278
void writeBinary(std::ostream &) const
Definition: Atoms.cpp:394
virtual void MD2double(const void *, double &) const =0
Convert a pointer to an MD-real to a double.
std::vector< int > indexToBeSent
Definition: Atoms.h:108
Class containing wrappers to MPI.
Definition: Communicator.h:44
STL namespace.
bool energyHasBeenSet
Definition: Atoms.h:65
MDAtomsBase * mdatoms
Definition: Atoms.h:79
DomainDecomposition dd
Definition: Atoms.h:117
virtual void setm(void *m)=0
Set a pointer to the mass array in the MD code.
std::vector< Communicator::Request > mpi_request_index
Definition: Atoms.h:104
std::vector< Vector > positions
Definition: Atoms.h:50
void const char const char int * n
Definition: Matrix.h:42
void shareAll()
Definition: Atoms.cpp:138
Definition: Pbc.h:38
std::vector< ActionWithVirtualAtom * > virtualAtomsActions
Definition: Atoms.h:54
double energy
Definition: Atoms.h:61
void remove(const ActionAtomistic *)
Definition: Atoms.cpp:265
void Allgather(const T *, int, T *, int)
Definition: Communicator.h:166
double timestep
Definition: Atoms.h:89
void double2MD(const double &d, void *m) const
Definition: Atoms.cpp:314
std::vector< Communicator::Request > mpi_request_positions
Definition: Atoms.h:103
double getKBoltzmann() const
Definition: Atoms.cpp:407
virtual void setUnits(const Units &units, const Units &MDUnits)=0
Set internal and MD units.
int Get_rank() const
Obtain the rank of the present process.
void readBinary(std::istream &)
Definition: Atoms.cpp:400
std::vector< int > indexToBeReceived
Definition: Atoms.h:109
void createFullList(int *)
Definition: Atoms.cpp:330
bool boxHasBeenSet
Definition: Atoms.h:69
Action used to create objects that access the positions of the atoms from the MD code.
bool dataCanBeSet
Definition: Atoms.h:63
const double & getEnergy() const
Get energy units as double.
Definition: Units.h:90
const double & getTime() const
Get time units as double.
Definition: Units.h:100
void setNatoms(int)
Definition: Atoms.cpp:250
void setEnergy(void *)
Definition: Atoms.cpp:102
const double kBoltzmann(0.0083144621)
Boltzman constant in kj/K.
std::vector< double > positionsToBeReceived
Definition: Atoms.h:107
Inherit from here if you are calculating the position of a virtual atom (eg a center of mass) ...
void startStep()
Definition: Atoms.cpp:66
void setMasses(void *)
Definition: Atoms.cpp:83
void resizeVectors(unsigned)
Definition: Atoms.cpp:363
void setAtomsGatindex(int *)
Definition: Atoms.cpp:289
double md_energy
Definition: Atoms.h:59
Units MDUnits
Definition: Atoms.h:83
virtual void setc(void *m)=0
Set a pointer to the charge array in the MD code.
virtual void rescaleForces(const std::vector< int > &index, double factor)=0
Rescale all the forces, including the virial.
void Recv(T *, int, int, int, Status &)
Definition: Communicator.h:200
unsigned index() const
Returns the index number.
Definition: AtomNumber.h:89
virtual void double2MD(const double &, void *) const =0
Convert a double to a pointer to an MD-real.
void init()
Definition: Atoms.cpp:350
virtual void setBox(void *)=0
Set a pointer to the box array (3x3) in the MD code.
virtual void updateVirial(const Tensor &v) const =0
Increment the virial by an amount v.
Tensor virial
Definition: Atoms.h:57
Tensor box
Definition: Atoms.h:55
void const char const char int double int double double int int double int * m
Definition: Matrix.h:42
virtual void getPositions(const std::vector< int > &index, std::vector< Vector > &p) const =0
Retrieve selected positions.
virtual void setVirial(void *)=0
Set a pointer to the virial array (3x3) in the MD code.
void setDomainDecomposition(Communicator &)
Definition: Atoms.cpp:359
void clearFullList()
Definition: Atoms.cpp:346
bool chargesHaveBeenSet
Definition: Atoms.h:68
virtual void getBox(Tensor &) const =0
Retrieve box as a plumed Tensor.
virtual void setp(void *p)=0
Set a pointer to the positions array in the MD code.
unsigned forcesHaveBeenSet
Definition: Atoms.h:70
Main plumed object.
Definition: PlumedMain.h:71
Main plumed object.
Definition: Plumed.h:201
void insertGroup(const std::string &name, const std::vector< AtomNumber > &a)
Definition: Atoms.cpp:384
void setRealPrecision(int)
Definition: Atoms.cpp:302
unsigned positionsHaveBeenSet
Definition: Atoms.h:66
std::vector< int > gatindex
Definition: Atoms.h:93
virtual void updateForces(const std::vector< int > &index, const std::vector< Vector > &f)=0
Increment the force on selected atoms.
void Set_comm(MPI_Comm)
Set from a real MPI communicator.
double getTimeStep() const
Definition: Atoms.cpp:326
int Get_size() const
Obtain the number of processes.
std::vector< double > positionsToBeSent
Definition: Atoms.h:106
void const char const char int double * a
Definition: Matrix.h:42
void Allgatherv(const T *, int, T *, const int *, const int *)
Wrapper for MPI_Allgatherv.
Definition: Communicator.h:146
Units units
Definition: Atoms.h:84
int natoms
Definition: Atoms.h:49
void Sum(T *, int)
Wrapper for MPI_Allreduce with MPI_SUM.
Definition: Communicator.h:124
bool collectEnergy
Definition: Atoms.h:64
void setForces(void *)
Definition: Atoms.cpp:109
Request Isend(const T *, int, int, int)
Definition: Communicator.h:183
void updateUnits()
Definition: Atoms.cpp:318
void setBox(const Tensor &b)
Set the lattice vectors.
Definition: Pbc.cpp:115
std::vector< int > fullList
Definition: Atoms.h:77
void MD2double(const void *m, double &d) const
Definition: Atoms.cpp:311
bool naturalUnits
Definition: Atoms.h:86
void setPositions(void *)
Definition: Atoms.cpp:77
void share()
Definition: Atoms.cpp:128
virtual void getCharges(const std::vector< int > &index, std::vector< double > &c) const =0
Retrieve selected charges.
void setBox(void *)
Definition: Atoms.cpp:72
std::map< std::string, std::vector< AtomNumber > > groups
Definition: Atoms.h:73
Pbc & pbc
Definition: Atoms.h:56
static MDAtomsBase * create(unsigned n)
Creates an MDAtomsTyped object such that sizeof(T)==n.
Definition: MDAtoms.cpp:224