Simpatico  v1.10
SerializeConfigIo.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 "SerializeConfigIo.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  { setClassName("SerializeConfigIo"); }
47 
48  /*
49  * Constructor.
50  */
52  : ConfigIo(simulation)
53  { setClassName("SerializeConfigIo"); }
54 
55  /*
56  * Private method to load Group<N> objects. (Call on all processors).
57  */
58  template <int N>
59  int SerializeConfigIo::loadGroups(Serializable::IArchive& ar,
60  GroupDistributor<N>& distributor)
61  {
62  int nGroup = 0; // Total number of groups in archive
63  if (domain().isMaster()) {
64  ar >> nGroup;
65  Group<N>* groupPtr;
66  distributor.setup();
67  for (int i = 0; i < nGroup; ++i) {
68  groupPtr = distributor.newPtr();
69  ar >> *groupPtr;
70  distributor.add();
71  }
72  // Send any groups not sent previously.
73  distributor.send();
74  } else { // If I am not the master processor
75  // Receive all groups into BondStorage
76  distributor.receive();
77  }
78  return nGroup; // Valid only on master
79  }
80 
81  /*
82  * Load a configuration from input archive.
83  */
85  {
86  // Preconditions
87  if (atomStorage().nAtom()) {
88  UTIL_THROW("Atom storage is not empty (has local atoms)");
89  }
90  if (atomStorage().nGhost()) {
91  UTIL_THROW("Atom storage is not empty (has ghost atoms)");
92  }
93  if (atomStorage().isCartesian()) {
94  UTIL_THROW("Atom storage set for Cartesian coordinates");
95  }
96 
97  // Load and broadcast boundary
98  if (domain().isMaster()) {
99  ar >> boundary();
100  }
101  #if UTIL_MPI
102  bcast(domain().communicator(), boundary(), 0);
103  #endif
104 
105  // Load atoms
106  int nAtom; // Total number of atoms in archive
107  if (domain().isMaster()) {
108 
109  ar >> nAtom;
110  int totalAtomCapacity = atomStorage().totalAtomCapacity();
111 
112  #ifdef UTIL_MPI
113  //Initialize the send buffer.
115  #endif
116 
117  // Read atoms
118  Vector r;
119  Atom* atomPtr;
120  AtomContext* contextPtr;
121  int id;
122  int typeId;
123  for (int i = 0; i < nAtom; ++i) {
124 
125  // Get pointer to new atom in distributor memory.
126  atomPtr = atomDistributor().newAtomPtr();
127 
128  ar >> id;
129  ar >> typeId;
130  if (id < 0 || id >= totalAtomCapacity) {
131  UTIL_THROW("Invalid atom id");
132  }
133  if (typeId < 0) {
134  UTIL_THROW("Negative atom type id");
135  }
136  atomPtr->setId(id);
137  atomPtr->setTypeId(typeId);
138  ar >> atomPtr->groups();
139  if (Atom::hasAtomContext()) {
140  contextPtr = &atomPtr->context();
141  ar >> contextPtr->speciesId;
142  ar >> contextPtr->moleculeId;
143  ar >> contextPtr->atomId;
144  }
145  ar >> r;
146  boundary().transformCartToGen(r, atomPtr->position());
147  ar >> atomPtr->velocity();
148 
149  // Add atom to list for sending.
151  }
152 
153  // Send any atoms not sent previously.
154  atomDistributor().send();
155 
156  } else { // If I am not the master processor
158  }
159 
160  // Validate atom distribution:
161  // Check that all are accounted for and on correct processor
162  int nAtomAll;
163  nAtomAll = atomDistributor().validate();
164  if (domain().isMaster()) {
165  if (nAtomAll != nAtom) {
166  UTIL_THROW("nAtomAll != nAtom after distribution");
167  }
168  }
169 
170  // Load groups
171  bool hasGhosts = false;
172  #ifdef SIMP_BOND
173  if (bondStorage().capacity()) {
174  loadGroups<2>(ar, bondDistributor());
175  bondStorage().isValid(atomStorage(), domain().communicator(), hasGhosts);
176  // Set atom "mask" values
177  if (maskPolicy == MaskBonded) {
178  setAtomMasks();
179  }
180  }
181  #endif
182  #ifdef SIMP_ANGLE
183  if (angleStorage().capacity()) {
184  loadGroups<3>(ar, angleDistributor());
185  angleStorage().isValid(atomStorage(), domain().communicator(),
186  hasGhosts);
187  }
188  #endif
189  #ifdef SIMP_DIHEDRAL
190  if (dihedralStorage().capacity()) {
191  loadGroups<4>(ar, dihedralDistributor());
192  dihedralStorage().isValid(atomStorage(), domain().communicator(),
193  hasGhosts);
194  }
195  #endif
196 
197  }
198 
199  /*
200  * Private method to save Group<N> objects.
201  */
202  template <int N>
203  int SerializeConfigIo::saveGroups(Serializable::OArchive& ar,
204  GroupStorage<N>& storage, GroupCollector<N>& collector)
205  {
206  Group<N>* groupPtr;
207  int nGroup;
208  storage.computeNTotal(domain().communicator());
209  nGroup = storage.nTotal();
210  if (domain().isMaster()) {
211  ar << nGroup;
212  collector.setup();
213  groupPtr = collector.nextPtr();
214  while (groupPtr) {
215  ar << *groupPtr;
216  groupPtr = collector.nextPtr();
217  }
218  } else {
219  collector.send();
220  }
221  return nGroup;
222  }
223 
224  /*
225  * Save the configuration to an archive.
226  */
228  {
229  // Write Boundary dimensions
230  if (domain().isMaster()) {
231  ar << boundary();
232  }
233 
234  // Save atoms
235  bool isCartesian = atomStorage().isCartesian();
236  atomStorage().computeNAtomTotal(domain().communicator());
237  if (domain().isMaster()) {
238 
239  int id;
240  int typeId;
241  int nAtom = atomStorage().nAtomTotal();
242  Vector r;
243  AtomContext* contextPtr;
244 
245  ar << nAtom;
246  atomCollector().setup();
247  Atom* atomPtr = atomCollector().nextPtr();
248  while (atomPtr) {
249  id = atomPtr->id();
250  typeId = atomPtr->typeId();
251  ar << id;
252  ar << typeId;
253  ar << atomPtr->groups();
254  if (Atom::hasAtomContext()) {
255  contextPtr = &atomPtr->context();
256  ar << contextPtr->speciesId;
257  ar << contextPtr->moleculeId;
258  ar << contextPtr->atomId;
259  }
260  if (isCartesian) {
261  ar << atomPtr->position();
262  } else {
263  boundary().transformGenToCart(atomPtr->position(), r);
264  ar << r;
265  }
266  ar << atomPtr->velocity();
267  atomPtr = atomCollector().nextPtr();
268  }
269 
270  } else {
271  atomCollector().send();
272  }
273 
274  // Save groups
275  #ifdef SIMP_BOND
276  if (bondStorage().capacity()) {
277  saveGroups<2>(ar, bondStorage(), bondCollector());
278  }
279  #endif
280  #ifdef SIMP_ANGLE
281  if (angleStorage().capacity()) {
282  saveGroups<3>(ar, angleStorage(), angleCollector());
283  }
284  #endif
285  #ifdef SIMP_DIHEDRAL
286  if (dihedralStorage().capacity()) {
287  saveGroups<4>(ar, dihedralStorage(), dihedralCollector());
288  }
289  #endif
290  }
291 
292  /*
293  * Read configuration file, using an input archive.
294  */
295  void SerializeConfigIo::readConfig(std::ifstream& file, MaskPolicy maskPolicy)
296  {
297  // Precondition
298  if (domain().isMaster() && !file.is_open()) {
299  UTIL_THROW("Error: File is not open on master");
300  }
301  // Other preconditions are enforced by loadConfig
302 
303  Serializable::IArchive ar(file);
304  loadConfig(ar, maskPolicy);
305  }
306 
307  /*
308  * Write configuration file, using an output file archive.
309  */
310  void SerializeConfigIo::writeConfig(std::ofstream& file)
311  {
312  // Preconditions
313  if (domain().isMaster() && !file.is_open()) {
314  UTIL_THROW("Error: File is not open on master");
315  }
316 
317  Serializable::OArchive ar(file);
318  saveConfig(ar);
319  }
320 
321 }
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 writeConfig(std::ofstream &file)
Write 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.
Saving / output archive for binary ostream.
#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
unsigned int & groups()
Get groups bit field by non-const reference.
int addAtom()
Process the active atom for sending.
Descriptor for context of an Atom within a molecule and species.
Definition: AtomContext.h:21
Class for collecting Groups from processors to master processor.
int speciesId
Index of the species of molecule.
Definition: AtomContext.h:27
void loadConfig(Serializable::IArchive &ar, MaskPolicy maskPolicy)
Load configuration from an archive.
Utility classes for scientific computation.
Definition: accumulators.mod:1
void setAtomMasks()
Set Mask data on all atoms.
virtual void readConfig(std::ifstream &file, MaskPolicy maskPolicy)
Read configuration file.
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?
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.
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.
Saving archive for binary istream.
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.
void saveConfig(Serializable::OArchive &ar)
Save configuration.
void send()
Send all atoms that have not be sent previously.
SerializeConfigIo()
Default constructor.
void transformCartToGen(const Vector &Rc, Vector &Rg) const
Transform Cartesian Vector to scaled / generalized coordinates.
Class template for distributing Group<N> objects among processors.