Simpatico  v1.10
ddMd/configIos/DdMdConfigIo.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 "DdMdConfigIo.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  */
44  DdMdConfigIo::DdMdConfigIo(bool hasMolecules)
45  : ConfigIo(),
46  hasMolecules_(hasMolecules)
47  { setClassName("DdMdConfigIo"); }
48 
49  /*
50  * Constructor.
51  */
52  DdMdConfigIo::DdMdConfigIo(Simulation& simulation, bool hasMolecules)
53  : ConfigIo(simulation),
54  hasMolecules_(hasMolecules)
55  { setClassName("DdMdConfigIo"); }
56 
57  /*
58  * Private method to read Group<N> objects.
59  */
60  template <int N>
61  void DdMdConfigIo::readGroups(std::ifstream& file,
62  const char* sectionLabel,
63  const char* nGroupLabel,
64  GroupDistributor<N>& distributor)
65  {
66  if (domain().isMaster()) {
67  int nGroup = 0; // Total number of groups in file
68  file >> Label(sectionLabel);
69  file >> Label(nGroupLabel) >> nGroup;
70  Group<N>* groupPtr;
71  distributor.setup();
72  for (int i = 0; i < nGroup; ++i) {
73  groupPtr = distributor.newPtr();
74  file >> *groupPtr;
75  distributor.add();
76  }
77  // Send any groups not sent previously.
78  distributor.send();
79  } else { // If I am not the master processor
80  // Receive all groups into BondStorage
81  distributor.receive();
82  }
83  }
84 
85  /*
86  * Read a configuration file.
87  */
88  void DdMdConfigIo::readConfig(std::ifstream& file, MaskPolicy maskPolicy)
89  {
90  // Precondition
91  if (atomStorage().nAtom()) {
92  UTIL_THROW("Atom storage is not empty (has local atoms)");
93  }
94  if (atomStorage().nGhost()) {
95  UTIL_THROW("Atom storage is not empty (has ghost atoms)");
96  }
97  if (atomStorage().isCartesian()) {
98  UTIL_THROW("Error: Atom storage is set for Cartesian coordinates");
99  }
100  if (domain().isMaster() && !file.is_open()) {
101  UTIL_THROW("Error: File is not open on master");
102  }
103  if (!Atom::hasAtomContext()) {
104  hasMolecules_ = false;
105  }
106 
107  // Read and broadcast boundary
108  if (domain().isMaster()) {
109  file >> Label("BOUNDARY");
110  file >> boundary();
111  }
112  #if UTIL_MPI
113  bcast(domain().communicator(), boundary(), 0);
114  #endif
115 
116  // Atoms
117  int nAtom; // Total number of atoms in file
118  if (domain().isMaster()) {
119 
120  // Read and distribute atoms
121  file >> Label("ATOMS");
122 
123  // Read number of atoms
124  file >> Label("nAtom") >> nAtom;
125 
126  int totalAtomCapacity = atomStorage().totalAtomCapacity();
127 
128  #if UTIL_MPI
129  //Initialize the send buffer.
131  #endif
132 
133  // Read atoms
134  Vector r;
135  Atom* atomPtr;
136  int id;
137  int typeId;
138 
139  int aId;
140  int mId;
141  int sId;
142 
143  for (int i = 0; i < nAtom; ++i) {
144 
145  // Get pointer to new atom in distributor memory.
146  atomPtr = atomDistributor().newAtomPtr();
147 
148  file >> id >> typeId;
149  if (id < 0 || id >= totalAtomCapacity) {
150  UTIL_THROW("Invalid atom id");
151  }
152  atomPtr->setId(id);
153  atomPtr->setTypeId(typeId);
154  if (hasMolecules_) {
155  file >> sId >> mId >> aId;
156  if (aId < 0) {
157  UTIL_THROW("Invalid Atom");
158  }
159  if (mId < 0) {
160  UTIL_THROW("Invalid Molecule");
161  }
162  if (sId < 0) {
163  UTIL_THROW("Invalid Specie");
164  }
165  atomPtr->context().atomId = aId;
166  atomPtr->context().moleculeId = mId;
167  atomPtr->context().speciesId = sId;
168  }
169  file >> r;
170  boundary().transformCartToGen(r, atomPtr->position());
171  file >> atomPtr->velocity();
172 
173  // Add atom to list for sending.
175 
176  }
177 
178  // Send any atoms not sent previously.
179  atomDistributor().send();
180 
181  } else { // If I am not the master processor
183  }
184 
185  // Validate atom distribution
186  // Checks that all are account for and on correct processor
187  int nAtomAll;
188  nAtomAll = atomDistributor().validate();
189  if (domain().isMaster()) {
190  if (nAtomAll != nAtom) {
191  UTIL_THROW("nAtomAll != nAtom after distribution");
192  }
193  }
194 
195  // Read Covalent Groups
196  bool hasGhosts = false;
197  #ifdef SIMP_BOND
198  if (bondStorage().capacity()) {
199  readGroups<2>(file, "BONDS", "nBond", bondDistributor());
200  bondStorage().isValid(atomStorage(), domain().communicator(), hasGhosts);
201  // Set atom "mask" values
202  if (maskPolicy == MaskBonded) {
203  setAtomMasks();
204  }
205  }
206  #endif
207  #ifdef SIMP_ANGLE
208  if (angleStorage().capacity()) {
209  readGroups<3>(file, "ANGLES", "nAngle", angleDistributor());
210  angleStorage().isValid(atomStorage(), domain().communicator(),
211  hasGhosts);
212  }
213  #endif
214  #ifdef SIMP_DIHEDRAL
215  if (dihedralStorage().capacity()) {
216  readGroups<4>(file, "DIHEDRALS", "nDihedral", dihedralDistributor());
217  dihedralStorage().isValid(atomStorage(), domain().communicator(),
218  hasGhosts);
219  }
220  #endif
221  }
222 
223  /*
224  * Private method to write Group<N> objects.
225  */
226  template <int N>
227  int DdMdConfigIo::writeGroups(std::ofstream& file,
228  const char* sectionLabel,
229  const char* nGroupLabel,
230  GroupStorage<N>& storage,
231  GroupCollector<N>& collector)
232  {
233  Group<N>* groupPtr;
234  int nGroup;
235  storage.computeNTotal(domain().communicator());
236  nGroup = storage.nTotal();
237  if (domain().isMaster()) {
238  file << std::endl;
239  file << sectionLabel << std::endl;
240  file << nGroupLabel << Int(nGroup, 10) << std::endl;
241  collector.setup();
242  groupPtr = collector.nextPtr();
243  while (groupPtr) {
244  file << *groupPtr << std::endl;
245  groupPtr = collector.nextPtr();
246  }
247  } else {
248  collector.send();
249  }
250  return nGroup;
251  }
252 
253  /*
254  * Write the configuration file.
255  */
256  void DdMdConfigIo::writeConfig(std::ofstream& file)
257  {
258  // Precondition
259  if (domain().isMaster() && !file.is_open()) {
260  UTIL_THROW("Error: File is not open on master");
261  }
262  if (!Atom::hasAtomContext()) {
263  hasMolecules_ = false;
264  }
265 
266  // Write Boundary dimensions
267  if (domain().isMaster()) {
268  file << "BOUNDARY" << std::endl << std::endl;
269  file << boundary() << std::endl;
270  file << std::endl;
271  }
272 
273  // Atoms
274  atomStorage().computeNAtomTotal(domain().communicator());
275  if (domain().isMaster()) {
276 
277  file << "ATOMS" << std::endl;
278  file << "nAtom" << Int(atomStorage().nAtomTotal(), 10) << std::endl;
279  atomCollector().setup();
280 
281  // Collect and write atoms
282  Vector r;
283  bool isCartesian = atomStorage().isCartesian();
284  Atom* atomPtr = atomCollector().nextPtr();
285  while (atomPtr) {
286  file << Int(atomPtr->id(), 10)
287  << Int(atomPtr->typeId(), 6);
288  if (isCartesian) {
289  r = atomPtr->position();
290  } else {
291  boundary().transformGenToCart(atomPtr->position(), r);
292  }
293  if (hasMolecules_) {
294  file << Int(atomPtr->context().speciesId, 6)
295  << Int(atomPtr->context().moleculeId, 10)
296  << Int(atomPtr->context().atomId, 6);
297  }
298  file << "\n" << r
299  << "\n" << atomPtr->velocity() << "\n";
300  atomPtr = atomCollector().nextPtr();
301  }
302 
303  } else {
304  atomCollector().send();
305  }
306 
307  // Write the groups
308  #ifdef SIMP_BOND
309  if (bondStorage().capacity()) {
310  writeGroups<2>(file, "BONDS", "nBond", bondStorage(), bondCollector());
311  }
312  #endif
313  #ifdef SIMP_ANGLE
314  if (angleStorage().capacity()) {
315  writeGroups<3>(file, "ANGLES", "nAngle", angleStorage(), angleCollector());
316  }
317  #endif
318  #ifdef SIMP_DIHEDRAL
319  if (dihedralStorage().capacity()) {
320  writeGroups<4>(file, "DIHEDRALS", "nDihedral", dihedralStorage(), dihedralCollector());
321  }
322  #endif
323 
324  }
325 
326 }
void computeNTotal(MPI::Intracomm &communicator)
Compute and store the number of distinct groups on all processors.
DdMdConfigIo(bool hasMolecules=false)
Default constructor.
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.
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.
virtual void writeConfig(std::ofstream &file)
Write configuration file.
#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.
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.
virtual void readConfig(std::ifstream &file, MaskPolicy maskPolicy)
Read configuration file.
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.
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.