Simpatico  v1.10
ddMd/configIos/LammpsConfigIo.cpp
1 /*
2 * Simpatico - Simulation Package for Polymeric and Molecular Liquids
3 *
4 * Copyright 2010 - 2017, The Regents of the University of Minnesota
5 * Distributed under the terms of the GNU General Public License.
6 */
7 
8 #include "LammpsConfigIo.h"
9 
10 #include <ddMd/simulation/Simulation.h>
11 #include <ddMd/communicate/Domain.h>
12 
13 #include <ddMd/storage/AtomStorage.h>
14 #ifdef SIMP_BOND
15 #include <ddMd/storage/BondStorage.h>
16 #endif
17 #ifdef SIMP_ANGLE
18 #include <ddMd/storage/AngleStorage.h>
19 #endif
20 #ifdef SIMP_DIHEDRAL
21 #include <ddMd/storage/DihedralStorage.h>
22 #endif
23 
24 #include <ddMd/communicate/GroupCollector.tpp>
25 #include <ddMd/communicate/GroupDistributor.tpp>
26 
27 #include <ddMd/communicate/Buffer.h>
28 #include <ddMd/chemistry/Atom.h>
29 #include <ddMd/chemistry/Bond.h>
30 #include <ddMd/chemistry/MaskPolicy.h>
31 #include <util/space/Vector.h>
32 #include <util/mpi/MpiSendRecv.h>
33 #include <util/format/Int.h>
34 #include <util/format/Dbl.h>
35 
36 namespace DdMd
37 {
38 
39  using namespace Util;
40 
41  /*
42  * Constructor.
43  */
45  : ConfigIo()
46  {}
47 
48  /*
49  * Constructor.
50  */
52  : ConfigIo(simulation)
53  {
54  nAtomType_ = simulation.nAtomType();
55  nBondType_ = 0;
56  nAngleType_ = 0;
57  nDihedralType_ = 0;
58  nImproperType_ = 0;
59  #ifdef SIMP_BOND
60  nBondType_ = simulation.nBondType();
61  #endif
62  #ifdef SIMP_ANGLE
63  nAngleType_ = simulation.nAngleType();
64  #endif
65  #ifdef SIMP_DIHEDRAL
66  nDihedralType_ = simulation.nDihedralType();
67  #endif
68  }
69 
70  /*
71  * Private method to read Group<N> objects.
72  */
73  template <int N>
74  void LammpsConfigIo::readGroups(std::ifstream& file,
75  const char* sectionLabel, int nGroup,
76  GroupDistributor<N>& distributor)
77  {
78  if (domain().isMaster()) {
79  file >> Label(sectionLabel);
80  Group<N>* groupPtr;
81  int i, j, k;
82  distributor.setup();
83  for (i = 0; i < nGroup; ++i) {
84  groupPtr = distributor.newPtr();
85  file >> k;
86  groupPtr->setId(k-1);
87  file >> k;
88  groupPtr->setTypeId(k-1);
89  for (j = 0; j < N; ++j) {
90  file >> k;
91  groupPtr->setAtomId(j, k-1);
92  }
93  distributor.add();
94  }
95  // Send any groups not sent previously.
96  distributor.send();
97  } else { // If I am not the master processor
98  // Receive all groups into BondStorage
99  distributor.receive();
100  }
101  }
102 
103  /*
104  * Read a configuration file.
105  */
106  void LammpsConfigIo::readConfig(std::ifstream& file, MaskPolicy maskPolicy)
107  {
108  // Precondition
109  if (atomStorage().nAtom()) {
110  UTIL_THROW("Atom storage is not empty (has local atoms)");
111  }
112  if (atomStorage().nGhost()) {
113  UTIL_THROW("Atom storage is not empty (has ghost atoms)");
114  }
115  if (atomStorage().isCartesian()) {
116  UTIL_THROW("Atom storage is set for Cartesian coordinates");
117  }
118  if (domain().isMaster() && !file.is_open()) {
119  UTIL_THROW("Error: File is not open on master");
120  }
121 
122  int nAtom;
123  int nBond;
124  int nAngle;
125  int nDihedral;
126  int nImproper;
127  int nAtomType;
128  int nBondType;
129  int nAngleType;
130  int nDihedralType;
131  int nImproperType;
132 
133  if (domain().isMaster()) {
134 
135  // Read and discard title line
136  std::string line;
137  std::getline(file, line);
138 
139  // Read numbers of atoms, bonds, etc.
140  file >> nAtom >> Label("atoms");
141  file >> nBond >> Label("bonds");
142  file >> nAngle >> Label("angles");
143  file >> nDihedral >> Label("dihedrals");
144  file >> nImproper >> Label("impropers");
145 
146  // Read numbers of atom types, bond types, etc.
147  file >> nAtomType >> Label("atom") >> Label("types");
148  file >> nBondType >> Label("bond") >> Label("types");
149  file >> nAngleType >> Label("angle") >> Label("types");
150  file >> nDihedralType >> Label("dihedral") >> Label("types");
151  file >> nImproperType >> Label("improper") >> Label("types");
152 
153  if (nAtomType > nAtomType_) {
154  UTIL_THROW("nAtomType > simulation().nAtomType()");
155  }
156  #ifdef SIMP_BOND
157  if (nBondType > nBondType_) {
158  UTIL_THROW("nAtomType > simulation().nBondType()");
159  }
160  #endif
161  #ifdef SIMP_ANGLE
162  if (nAngleType > nAngleType_) {
163  UTIL_THROW("nAngleype > simulation().nAngleType()");
164  }
165  #endif
166  #ifdef SIMP_DIHEDRAL
167  if (nDihedralType > nDihedralType_) {
168  UTIL_THROW("nDihedralType > simulation().nDihedralType()");
169  }
170  #endif
171  }
172 
173  // Read and broadcast boundary
174  Vector lengths;
175  Vector min;
176  Vector max;
177  if (domain().isMaster()) {
178  file >> min[0] >> max[0] >> Label("xlo") >> Label("xhi");
179  file >> min[1] >> max[1] >> Label("ylo") >> Label("yhi");
180  file >> min[2] >> max[2] >> Label("zlo") >> Label("zhi");
181  lengths.subtract(max, min);
182  boundary().setOrthorhombic(lengths);
183  }
184  #if UTIL_MPI
185  bcast(domain().communicator(), boundary(), 0);
186  #endif
187 
188  // Read particle masses (discard values)
189  double mass;
190  int atomTypeId;
191  if (domain().isMaster()) {
192  file >> Label("Masses");
193  for (int i = 0; i < nAtomType; ++i) {
194  file >> atomTypeId >> mass;
195  }
196  }
197 
198  /*
199  * Read atomic positions
200  *
201  * Atom tags must appear in order, numbered from 1
202  */
203  if (domain().isMaster()) {
204  file >> Label("Atoms");
205 
206  int totalAtomCapacity = atomStorage().totalAtomCapacity();
207 
208  //Initialize the send buffer.
210 
211  // Read atoms
212  Vector r(0.0);
213  Atom* atomPtr = 0;
214  int id;
215  int typeId;
216  int moleculeId;
217  IntVector shift;
218 
219  for (int i = 0; i < nAtom; ++i) {
220 
221  // Get pointer to new atom in distributor memory.
222  atomPtr = atomDistributor().newAtomPtr();
223 
224  file >> id >> moleculeId >> typeId;
225  if (id <= 0 || id > totalAtomCapacity) {
226  UTIL_THROW("Invalid atom id");
227  }
228  atomPtr->setId(id-1);
229  atomPtr->setTypeId(typeId-1);
230  file >> r;
231  atomPtr->position() += min; // Shift corner of Boundary to (0, 0, 0)
232  boundary().transformCartToGen(r, atomPtr->position());
233  file >> shift;
234 
235  // Add atom to list for sending.
237 
238  }
239 
240  // Send any atoms not sent previously.
241  atomDistributor().send();
242 
243  } else { // If I am not the master processor
245  }
246 
247  // Validate atom distribution
248  // Check that all atoms are accounted for and on correct processor
249  int nAtomAll;
250  nAtomAll = atomDistributor().validate();
251  if (domain().isMaster()) {
252  if (nAtomAll != nAtom) {
253  UTIL_THROW("nAtomAll != nAtom after distribution");
254  }
255  }
256 
257  bool hasGhosts = false;
258  #ifdef SIMP_BOND
259  if (bondStorage().capacity()) {
260  readGroups<2>(file, "Bonds", nBond, bondDistributor());
261  bondStorage().isValid(atomStorage(), domain().communicator(), hasGhosts);
262  //Set atom "mask" values
263  if (maskPolicy == MaskBonded) {
264  setAtomMasks();
265  }
266  }
267  #endif
268 
269  #ifdef SIMP_ANGLE
270  if (angleStorage().capacity()) {
271  readGroups<3>(file, "Angles", nAngle, angleDistributor());
272  angleStorage().isValid(atomStorage(), domain().communicator(), hasGhosts);
273  }
274  #endif
275 
276  #ifdef SIMP_DIHEDRAL
277  if (dihedralStorage().capacity()) {
278  readGroups<4>(file, "Dihedrals", nDihedral, dihedralDistributor());
279  dihedralStorage().isValid(atomStorage(), domain().communicator(), hasGhosts);
280  }
281  #endif
282 
283  }
284 
285  /*
286  * Private method to write Group<N> objects.
287  */
288  template <int N>
289  void LammpsConfigIo::writeGroups(std::ofstream& file,
290  const char* sectionLabel,
291  GroupStorage<N>& storage,
292  GroupCollector<N>& collector)
293  {
294  Group<N>* groupPtr;
295  int nGroup;
296  storage.computeNTotal(domain().communicator());
297  nGroup = storage.nTotal();
298  if (domain().isMaster()) {
299 
300  IoGroup<N> ioGroup;
301  std::vector<IoGroup <N> > groups;
302 
303  // Collect and sort groups
304  groups.reserve(nGroup);
305  groups.clear();
306  groups.insert(groups.end(), nGroup, ioGroup);
307  collector.setup();
308  groupPtr = collector.nextPtr();
309  int id;
310  int n = 0;
311  while (groupPtr) {
312  id = groupPtr->id();
313  groups[id].id = id;
314  groups[id].group = *groupPtr;
315  groupPtr = collector.nextPtr();
316  ++n;
317  }
318  if (n != nGroup) {
319  UTIL_THROW("Inconsistency in total number of groups");
320  }
321 
322  // Write groups
323  file << std::endl;
324  file << sectionLabel << std::endl;
325  file << std::endl;
326  int j, k;
327  for (id = 0; id < nGroup; ++id) {
328  if (id != groups[id].id) {
329  UTIL_THROW("Incorrect group id in ordered output");
330  }
331  k = groups[id].id + 1;
332  file << k;
333  k = groups[id].group.typeId() + 1;
334  file << " " << k;
335  for (j = 0; j < N; ++j) {
336  k = groups[id].group.atomId(j) + 1;
337  file << " " << k ;
338  }
339  file << std::endl;
340  }
341  file << std::endl;
342  } else {
343  collector.send();
344  }
345  }
346 
347  /*
348  * Write the configuration file.
349  */
350  void LammpsConfigIo::writeConfig(std::ofstream& file)
351  {
352  // Preconditions
353  if (domain().isMaster() && !file.is_open()) {
354  UTIL_THROW("Error: File is not open on master");
355  }
356 
357  using std::endl;
358 
359  // Atoms
360  atomStorage().computeNAtomTotal(domain().communicator());
361 
362  // Bonds
363  #ifdef SIMP_BOND
364  if (nBondType_) {
365  if (bondStorage().capacity()) {
366  bondStorage().computeNTotal(domain().communicator());
367  }
368  }
369  #endif
370  #ifdef SIMP_ANGLE
371  if (nAngleType_) {
372  if (angleStorage().capacity()) {
373  angleStorage().computeNTotal(domain().communicator());
374  }
375  }
376  #endif
377  #ifdef SIMP_DIHEDRAL
378  if (nDihedralType_) {
379  if (dihedralStorage().capacity()) {
380  dihedralStorage().computeNTotal(domain().communicator());
381  }
382  }
383  #endif
384 
385  if (domain().isMaster()) {
386 
387  // Write first line (skipped) and a blank line.
388  file << "LAMMPS data file" << endl;
389  file << endl;
390 
391  int nAtom = atomStorage().nAtomTotal();
392  int nBond = 0;
393  int nAngle = 0;
394  int nDihedral= 0;
395  int nImproper = 0;
396  #ifdef SIMP_BOND
397  if (nBondType_) {
398  nBond = bondStorage().nTotal();
399  }
400  #endif
401  #ifdef SIMP_ANGLE
402  if (nAngleType_) {
403  nAngle = angleStorage().nTotal();
404  }
405  #endif
406  #ifdef SIMP_DIHEDRAL
407  if (nDihedralType_) {
408  nDihedral = dihedralStorage().nTotal();
409  }
410  #endif
411 
412  // Write numbers of atoms, bonds, etc.
413  file << nAtom << " atoms " << endl;
414  file << nBond << " bonds " << endl;
415  file << nAngle << " angles " << endl;
416  file << nDihedral << " dihedrals " << endl;
417  file << nImproper << " impropers" << endl;
418 
419  // Write numbers of atom types, bond types, etc.
420  file << endl;
421  file << nAtomType_ << " atom types" << endl;
422  file << nBondType_ << " bond types" << endl;
423  file << nAngleType_ << " angle types" << endl;
424  file << nDihedralType_ << " dihedral types" << endl;
425  file << nImproperType_ << " improper types" << endl;
426 
427  // Write Boundary dimensions
428  file << endl;
429  Vector lengths = boundary().lengths();
430  file << Dbl(0.0) << Dbl(lengths[0]) << " xlo xhi" << endl;
431  file << Dbl(0.0) << Dbl(lengths[1]) << " ylo yhi" << endl;
432  file << Dbl(0.0) << Dbl(lengths[2]) << " zlo zhi" << endl;
433 
434  // Write masses (all set to 1.0 for now)
435  // lammps atom type = Simpatico atom type + 1
436  file << endl;
437  file << "Masses" << endl;
438  file << endl;
439  for (int iType = 0; iType < nAtomType_; ++iType) {
440  file << iType+1 << " " << 1.0 << endl;
441  }
442 
443  IoAtom atom;
444  atoms_.reserve(nAtom);
445  atoms_.clear();
446  atoms_.insert(atoms_.end(), nAtom, atom);
447 
448 
449  // Collect atoms
450  atomCollector().setup();
451  Vector r;
452  int id;
453  int n = 0;
454  bool isCartesian = atomStorage().isCartesian();
455  Atom* atomPtr = atomCollector().nextPtr();
456  while (atomPtr) {
457  id = atomPtr->id();
458  atoms_[id].id = id;
459  atoms_[id].typeId = atomPtr->typeId();
460  if (isCartesian) {
461  r = atomPtr->position();
462  } else {
463  boundary().transformGenToCart(atomPtr->position(), r);
464  }
465  atoms_[id].position = r;
466  atomPtr = atomCollector().nextPtr();
467  ++n;
468  }
469  if (n != nAtom) {
470  UTIL_THROW("Inconsistency in number of atoms");
471  }
472 
473  // Write atom positions
474  // lammps atom tag = Simpatico atom id + 1
475  // lammps molecule id = Simpatico molecule id + 1
476  file << endl;
477  file << "Atoms" << endl;
478  file << endl;
479  int shift = 0;
480  for (id = 0; id < nAtom; ++id) {
481  if (id != atoms_[id].id) {
482  UTIL_THROW("Incorrect atom id in ordered output");
483  }
484  file << id+1 << " " << "1 " << atoms_[id].typeId + 1
485  << " " << atoms_[id].position;
486  for (int i = 0; i < Dimension; ++i) {
487  file << " " << shift;
488  }
489  file << std::endl;
490  }
491 
492  // Write atomic velocities
493  // lammps atom tag = Simpatico atom id + 1
494  // lammps molecule id = Simpatico molecule id + 1
495  /*
496  file << endl;
497  file << "Velocities" << endl;
498  file << endl;
499  for (id = 0; id < nAtom; ++id) {
500  if (id != atoms_[id].id) {
501  UTIL_THROW("Incorrect atom id in ordered output");
502  }
503  file << id+1 << " " << atoms_[id].velocity;
504  file << std::endl;
505  }
506  */
507  } else {
508  atomCollector().send();
509  }
510 
511  // Write the groups
512  #ifdef SIMP_BOND
513  if (nBondType_) {
514  if (bondStorage().capacity()) {
515  writeGroups<2>(file, "Bonds", bondStorage(), bondCollector());
516  }
517  }
518  #endif
519  #ifdef SIMP_ANGLE
520  if (nAngleType_) {
521  if (angleStorage().capacity()) {
522  writeGroups<3>(file, "Angles", angleStorage(), angleCollector());
523  }
524  }
525  #endif
526  #ifdef SIMP_DIHEDRAL
527  if (nDihedralType_) {
528  if (dihedralStorage().capacity()) {
529  writeGroups<4>(file, "Dihedrals", dihedralStorage(), dihedralCollector());
530  }
531  }
532  #endif
533 
534  }
535 
536 }
void computeNTotal(MPI::Intracomm &communicator)
Compute and store the number of distinct groups on all processors.
void setup()
Setup master processor for receiving.
GroupDistributor< 2 > & bondDistributor()
Get the bondDistributor by reference.
int typeId() const
Get atom type index.
const int Dimension
Dimensionality of space.
Definition: Dimension.h:19
GroupCollector< 4 > & dihedralCollector()
Get the dihedral collector by reference.
A Vector is a Cartesian vector.
Definition: Vector.h:75
AtomStorage & atomStorage()
Get AtomStorage by reference.
Atom * newAtomPtr()
Returns pointer an address available for a new Atom.
int nAtomTotal() const
Get total number of atoms on all processors.
void add()
Add a group to the cache for sending, send if necessary.
Group< N > * nextPtr()
Return a pointer to the next available atom, or null.
BondStorage & bondStorage()
Get BondStorage by reference.
void setTypeId(int Id)
Set the atom type index.
void setOrthorhombic(const Vector &lengths)
Set unit cell dimensions for orthorhombic boundary.
void setId(int Id)
Set unique global id for this Atom.
const Vector & lengths() const
Get Vector of unit cell lengths by const reference.
Domain & domain()
Get the Domain by reference.
Vector & position()
Get position Vector by reference.
AtomCollector & atomCollector()
Get the AtomCollector by reference.
void send()
Send all atoms to the master.
GroupDistributor< 3 > & angleDistributor()
Get the angle distributor by reference.
virtual void writeConfig(std::ofstream &file)
Write configuration file.
Wrapper for a double precision number, for formatted ostream output.
Definition: Dbl.h:39
int nBondType()
Get maximum number of bond types.
A point particle in an MD simulation.
Parallel domain decomposition (DD) MD simulation.
Main object for a domain-decomposition MD simulation.
int id() const
Get unique global index for this atom.
int capacity() const
Return capacity for groups on this processor.
virtual void readConfig(std::ifstream &file, MaskPolicy maskPolicy)
Read configuration file.
int nDihedralType()
Get maximum number of dihedral types.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
void setTypeId(int typeId)
Set the group type id for this group.
AtomDistributor & atomDistributor()
Get the AtomDistributor by reference.
void bcast(MPI::Intracomm &comm, T &data, int root)
Broadcast a single T value.
Definition: MpiSendRecv.h:134
int addAtom()
Process the active atom for sending.
Class for collecting Groups from processors to master processor.
LammpsConfigIo()
Default constructor.
Utility classes for scientific computation.
Definition: accumulators.mod:1
void setAtomMasks()
Set Mask data on all atoms.
Atom * nextPtr()
Return a pointer to the next available atom, or null.
GroupDistributor< 4 > & dihedralDistributor()
Get the dihedral distributor by reference.
MaskPolicy
Enumeration of policies for suppressing ("masking") some pair interactions.
virtual bool isValid(AtomStorage &atomStorage, MPI::Intracomm &communicator, bool hasGhosts)
Return true if the container is valid, or throw an Exception.
Group< N > * newPtr()
Returns pointer an address available for a new Group<N>.
Boundary & boundary()
Get Boundary by reference.
void receive()
Receive all atoms sent by master processor.
A container for all the Group<N> objects on this processor.
void send()
Send all atoms that have not be sent previously.
void transformGenToCart(const Vector &Rg, Vector &Rc) const
Transform Vector of generalized coordinates to Cartesian Vector.
GroupCollector< 2 > & bondCollector()
Get the bond collector by reference.
void computeNAtomTotal(MPI::Intracomm &communicator)
Compute the total number of local atoms on all processors.
int totalAtomCapacity() const
Return maximum number of atoms on all processors.
void setup()
Initialization before the loop over atoms on master processor.
A label string in a file format.
Definition: Label.h:36
int nTotal() const
Return total number of distinct groups on all processors.
int validate()
Validate distribution of atoms after completion.
Abstract reader/writer for configuration files.
void send()
Send all groups on this processor to the master processor.
void setup()
Initialize Buffer for sending.
bool isCartesian() const
Are atom coordinates Cartesian (true) or generalized (false)?
This file contains templates for global functions send<T>, recv<T> and bcast<T>.
void receive()
Receive all atoms sent by master processor.
Vector & subtract(const Vector &v1, const Vector &v2)
Subtract vector v2 from v1.
Definition: Vector.h:672
AngleStorage & angleStorage()
Get AngleStorage by reference.
An IntVector is an integer Cartesian vector.
Definition: IntVector.h:73
int nAtomType()
Get maximum number of atom types.
A group of covalently interacting atoms.
void setup()
Setup master processor for receiving.
GroupCollector< 3 > & angleCollector()
Get the angle collector by reference.
void setAtomId(int i, int atomId)
Set the id for a specific atom.
int nAngleType()
Get maximum number of angle types.
DihedralStorage & dihedralStorage()
Get DihedralStorage by reference.
int id() const
Get the global id for this group.
void send()
Send all atoms that have not be sent previously.
void setId(int id)
Set the global id for this group.
void transformCartToGen(const Vector &Rc, Vector &Rg) const
Transform Cartesian Vector to scaled / generalized coordinates.
Class template for distributing Group<N> objects among processors.