Simpatico  v1.10
DdMdOrderedConfigIo.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 "DdMdOrderedConfigIo.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  hasMolecules_(hasMolecules)
47  { setClassName("DdMdOrderedConfigIo"); }
48 
49  /*
50  * Constructor.
51  */
52  DdMdOrderedConfigIo::DdMdOrderedConfigIo(Simulation& simulation, bool hasMolecules)
53  : ConfigIo(simulation),
54  hasMolecules_(hasMolecules)
55  { setClassName("DdMdOrderedConfigIo"); }
56 
57  /*
58  * Private method to read Group<N> objects.
59  */
60  template <int N>
61  void DdMdOrderedConfigIo::readGroups(std::ifstream& file,
62  const char* sectionLabel,
63  const char* nGroupLabel,
64  GroupDistributor<N>& distributor)
65  {
66  if (domain().isMaster()) {
67  int nGroup; // Total number of groups in file
68  file >> Label(sectionLabel);
69  file >> Label(nGroupLabel) >> nGroup;
70 
71  Group<N>* groupPtr;
72  distributor.setup();
73  for (int i = 0; i < nGroup; ++i) {
74  groupPtr = distributor.newPtr();
75  file >> *groupPtr;
76  distributor.add();
77  }
78  // Send any groups not sent previously.
79  distributor.send();
80  } else { // If I am not the master processor
81  // Receive all groups into BondStorage
82  distributor.receive();
83  }
84  // return nGroup;
85  }
86 
87  /*
88  * Read a configuration file.
89  */
90  void DdMdOrderedConfigIo::readConfig(std::ifstream& file, MaskPolicy maskPolicy)
91  {
92  // Precondition
93  if (atomStorage().nAtom()) {
94  UTIL_THROW("Atom storage is not empty (has local atoms)");
95  }
96  if (atomStorage().nGhost()) {
97  UTIL_THROW("Atom storage is not empty (has ghost atoms)");
98  }
99  if (atomStorage().isCartesian()) {
100  UTIL_THROW("Atom storage is set for Cartesian coordinates");
101  }
102  if (domain().isMaster() && !file.is_open()) {
103  UTIL_THROW("Error: File is not open on master");
104  }
105  if (!Atom::hasAtomContext()) {
106  hasMolecules_ = false;
107  }
108 
109  // Read and broadcast boundary
110  if (domain().isMaster()) {
111  file >> Label("BOUNDARY");
112  file >> boundary();
113  }
114  #if UTIL_MPI
115  bcast(domain().communicator(), boundary(), 0);
116  #endif
117 
118  // Atoms
119  int nAtom; // Total number of atoms in file
120  if (domain().isMaster()) {
121 
122  // Read and distribute atoms
123  file >> Label("ATOMS");
124 
125  // Read number of atoms
126  file >> Label("nAtom") >> nAtom;
127 
128  int totalAtomCapacity = atomStorage().totalAtomCapacity();
129 
130  #if UTIL_MPI
131  //Initialize the send buffer.
133  #endif
134 
135  // Read atoms
136  Vector r;
137  Atom* atomPtr;
138  int id;
139  int typeId;
140 
141  int aId;
142  int mId;
143  int sId;
144 
145  for (int i = 0; i < nAtom; ++i) {
146 
147  // Get pointer to new atom in distributor memory.
148  atomPtr = atomDistributor().newAtomPtr();
149 
150  file >> id >> typeId;
151  if (id < 0 || id >= totalAtomCapacity) {
152  UTIL_THROW("Invalid atom id");
153  }
154  atomPtr->setId(id);
155  atomPtr->setTypeId(typeId);
156 
157  if (hasMolecules_) {
158  file >> sId >> mId >> aId;
159  if (sId < 0) {
160  UTIL_THROW("species Id < 0");
161  }
162  if (mId < 0) {
163  UTIL_THROW("molecule Id < 0");
164  }
165  if (aId < 0) {
166  UTIL_THROW("atom Id < 0");
167  }
168  atomPtr->context().speciesId = sId;
169  atomPtr->context().moleculeId = mId;
170  atomPtr->context().atomId = aId;
171  }
172 
173  file >> r;
174  boundary().transformCartToGen(r, atomPtr->position());
175  file >> atomPtr->velocity();
176 
177  // Add atom to list for sending.
179 
180  }
181 
182  // Send any atoms not sent previously.
183  atomDistributor().send();
184 
185  } else { // If I am not the master processor
187  }
188 
189  // Validate atom distribution
190  // Check that all atoms are accounted for and on correct processor
191  {
192  int nAtomAll = atomDistributor().validate();
193  if (domain().isMaster()) {
194  if (nAtomAll != nAtom) {
195  UTIL_THROW("nAtomAll != nAtom after distribution");
196  }
197  }
198  }
199 
200  // Read covalent groups
201  bool hasGhosts = false;
202  #ifdef SIMP_BOND
203  if (bondStorage().capacity()) {
204  readGroups<2>(file, "BONDS", "nBond", bondDistributor());
205  bondStorage().isValid(atomStorage(), domain().communicator(), hasGhosts);
206  // Set atom "mask" values
207  if (maskPolicy == MaskBonded) {
208  setAtomMasks();
209  }
210  }
211  #endif
212  #ifdef SIMP_ANGLE
213  if (angleStorage().capacity()) {
214  readGroups<3>(file, "ANGLES", "nAngle", angleDistributor());
215  angleStorage().isValid(atomStorage(), domain().communicator(),
216  hasGhosts);
217  }
218  #endif
219  #ifdef SIMP_DIHEDRAL
220  if (dihedralStorage().capacity()) {
221  readGroups<4>(file, "DIHEDRALS", "nDihedral", dihedralDistributor());
222  dihedralStorage().isValid(atomStorage(), domain().communicator(),
223  hasGhosts);
224  }
225  #endif
226 
227  }
228 
229  /*
230  * Private method to write Group<N> objects.
231  */
232  template <int N>
233  int DdMdOrderedConfigIo::writeGroups(std::ofstream& file,
234  const char* sectionLabel,
235  const char* nGroupLabel,
236  GroupStorage<N>& storage,
237  GroupCollector<N>& collector)
238  {
239  Group<N>* groupPtr;
240  int nGroup;
241  storage.computeNTotal(domain().communicator());
242  nGroup = storage.nTotal();
243  if (domain().isMaster()) {
244  file << std::endl;
245  file << sectionLabel << std::endl;
246  file << nGroupLabel << Int(nGroup, 10) << std::endl;
247 
248  IoGroup<N> ioGroup;
249  std::vector<IoGroup <N> > groups;
250  groups.reserve(nGroup);
251  groups.clear();
252  groups.insert(groups.end(), nGroup, ioGroup);
253 
254  collector.setup();
255  groupPtr = collector.nextPtr();
256  int id;
257  int n = 0;
258  while (groupPtr) {
259  id = groupPtr->id();
260  groups[id].id = id;
261  groups[id].group = *groupPtr;
262  groupPtr = collector.nextPtr();
263  ++n;
264  }
265  if (n != nGroup) {
266  UTIL_THROW("Something is rotten in Denmark");
267  }
268  for (id = 0; id < nGroup; ++id) {
269  if (id != groups[id].id) {
270  UTIL_THROW("Something is rotten in Denmark");
271  }
272  file << groups[id].group << std::endl;
273  }
274  file << std::endl;
275  } else {
276  collector.send();
277  }
278  return nGroup;
279  }
280 
281  /*
282  * Write the configuration file.
283  */
284  void DdMdOrderedConfigIo::writeConfig(std::ofstream& file)
285  {
286  // Precondition
287  if (domain().isMaster() && !file.is_open()) {
288  UTIL_THROW("Error: File is not open on master");
289  }
290  if (!Atom::hasAtomContext()) {
291  hasMolecules_ = false;
292  }
293 
294  // Write Boundary dimensions
295  if (domain().isMaster()) {
296  file << "BOUNDARY" << std::endl << std::endl;
297  file << boundary() << std::endl;
298  file << std::endl;
299  }
300 
301  // Atoms
302  atomStorage().computeNAtomTotal(domain().communicator());
303  if (domain().isMaster()) {
304  int nAtom = atomStorage().nAtomTotal();
305  atomCollector().setup();
306 
307  file << "ATOMS" << std::endl;
308  file << "nAtom" << Int(nAtom, 10) << std::endl;
309 
310  // Set up array of nAtom default-constructed elements.
311  IoAtom atom;
312  atoms_.reserve(nAtom);
313  atoms_.clear();
314  atoms_.insert(atoms_.end(), nAtom, atom);
315 
316  // Collect unordered atoms and store in order in atoms_ .
317  Vector r;
318  int id;
319  int n = 0;
320  bool isCartesian = atomStorage().isCartesian();
321  Atom* atomPtr = atomCollector().nextPtr();
322  while (atomPtr) {
323  id = atomPtr->id();
324  if (isCartesian) {
325  r = atomPtr->position();
326  } else {
327  boundary().transformGenToCart(atomPtr->position(), r);
328  }
329  atoms_[id].position = r;
330  atoms_[id].velocity = atomPtr->velocity();
331  atoms_[id].typeId = atomPtr->typeId();
332  atoms_[id].id = id;
333  if (hasMolecules_) {
334  atoms_[id].context = atomPtr->context();
335  }
336  atomPtr = atomCollector().nextPtr();
337  ++n;
338  }
339  if (n != nAtom) {
340  UTIL_THROW("Something is rotten in Denmark");
341  }
342 
343  // Iterate through atoms_ array to write atoms data.
344  for (id = 0; id < nAtom; ++id) {
345  if (id != atoms_[id].id) {
346  UTIL_THROW("Something is rotten in Denmark");
347  }
348  file << Int(id, 10) << Int(atoms_[id].typeId, 6);
349  if (hasMolecules_) {
350  file << Int(atoms_[id].context.speciesId, 6)
351  << Int(atoms_[id].context.moleculeId, 6)
352  << Int(atoms_[id].context.atomId, 6);
353  }
354  file << "\n" << atoms_[id].position
355  << "\n" << atoms_[id].velocity
356  << "\n";
357  }
358 
359  } else {
360  atomCollector().send();
361  }
362 
363  // Write the groups
364  #ifdef SIMP_BOND
365  if (bondStorage().capacity()) {
366  writeGroups<2>(file, "BONDS", "nBond", bondStorage(), bondCollector());
367  }
368  #endif
369  #ifdef SIMP_ANGLE
370  if (angleStorage().capacity()) {
371  writeGroups<3>(file, "ANGLES", "nAngle", angleStorage(), angleCollector());
372  }
373  #endif
374  #ifdef SIMP_DIHEDRAL
375  if (dihedralStorage().capacity()) {
376  writeGroups<4>(file, "DIHEDRALS", "nDihedral", dihedralStorage(), dihedralCollector());
377  }
378  #endif
379 
380  }
381 
382 }
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.
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.
virtual void readConfig(std::ifstream &file, MaskPolicy maskPolicy)
Read configuration file.
int nAtomTotal() const
Get total number of atoms on all processors.
void add()
Add a group to the cache for sending, send if necessary.
int moleculeId
Index of molecule within its molecular species.
Definition: AtomContext.h:32
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 setId(int Id)
Set unique global id for this Atom.
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.
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.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
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.
int speciesId
Index of the species of molecule.
Definition: AtomContext.h:27
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.
static bool hasAtomContext()
Is AtomContext data enabled?
Wrapper for an int, for formatted ostream output.
Definition: Int.h:36
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.
DdMdOrderedConfigIo(bool hasMolecules)
Default constructor.
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.
AtomContext & context()
Get the AtomContext struct by non-const reference.
int validate()
Validate distribution of atoms after completion.
Abstract reader/writer for configuration files.
Vector & velocity()
Get velocity Vector by reference.
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.
AngleStorage & angleStorage()
Get AngleStorage by reference.
void setClassName(const char *className)
Set class name string.
A group of covalently interacting atoms.
void setup()
Setup master processor for receiving.
int atomId
Index of atom within its parent molecule.
Definition: AtomContext.h:43
GroupCollector< 3 > & angleCollector()
Get the angle collector by reference.
DihedralStorage & dihedralStorage()
Get DihedralStorage by reference.
virtual void writeConfig(std::ofstream &file)
Write configuration file.
int id() const
Get the global id for this group.
void send()
Send all atoms that have not be sent previously.
void transformCartToGen(const Vector &Rc, Vector &Rg) const
Transform Cartesian Vector to scaled / generalized coordinates.
Class template for distributing Group<N> objects among processors.