OpenMPCD
VTFSnapshotFile.hpp
Go to the documentation of this file.
1 /**
2  * @file
3  * Defines the `OpenMPCD::VTFSnapshotFile` class.
4  */
5 
6 #ifndef OPENMPCD_VTFSNAPSHOTFILE_HPP
7 #define OPENMPCD_VTFSNAPSHOTFILE_HPP
8 
11 #include <OpenMPCD/Types.hpp>
12 #include <OpenMPCD/Vector3D.hpp>
13 
14 #include <boost/optional.hpp>
15 
16 #include <fstream>
17 #include <list>
18 #include <set>
19 #include <sstream>
20 #include <string>
21 #include <vector>
22 
23 namespace OpenMPCD
24 {
25 
26 /**
27  * Representation of a simulation snapshot file in the `VTF` format.
28  *
29  * The `VTF` format is documented at the following URL:
30  * https://github.com/olenz/vtfplugin/wiki/VTF-format
31  *
32  * A snapshot file can be opened either in write mode or in read mode.
33  * The instance is in read mode if it is passed a path to an existing file,
34  * and in write mode otherwise.
35  * In read mode, the snapshot cannot be changed (trying to do that results
36  * in an instance of `OpenMPCD::InvalidCallException` being thrown).
37  * In write mode, one cannot read data that does not belong to the structure
38  * block.
39  *
40  * A VTF file starts with up to one structure block, followed by an arbitrary
41  * number of timestep blocks.
42  * After data that does not belong to the structure block has been supplied,
43  * structure block information cannot be changed anymore; any attempts to do
44  * so result in an instance of `OpenMPCD::InvalidCallException` being thrown.
45  *
46  * It is not guaranteed that data will be written to the snapshot file
47  * immediately. Writes may be cached until the object is destroyed.
48  */
50 {
51  public:
52  /**
53  * Collection of properties of atoms.
54  */
56  {
57  boost::optional<FP> radius; ///< The radius of the atom.
58  boost::optional<std::string> name; ///< The name of the atom.
59  boost::optional<std::string> type; ///< The type of the atom.
60  };
61 
62  public:
63  /**
64  * The constructor.
65  *
66  * The `path_` given will be used to open the snapshot file.
67  * If the file does not exist, it will be created, and the instance is
68  * in write mode. Otherwise, the instance is in read mode.
69  *
70  * @throw OpenMPCD::IOException
71  * Throws if the file could not be opened or created.
72  * @throw OpenMPCD::MalformedFileException
73  * In read mode, throws if the VTF file is malformed.
74  *
75  * @param[in] path_ The path to the snapshot file.
76  */
77  VTFSnapshotFile(const std::string& path_);
78 
79  /**
80  * The destructor.
81  */
82  virtual ~VTFSnapshotFile();
83 
84  public:
85  /**
86  * Returns whether the instance is in write mode.
87  */
88  bool isInWriteMode() const
89  {
90  return writeModeFlag;
91  }
92 
93  /**
94  * Returns whether the instance is in read mode.
95  */
96  bool isInReadMode() const
97  {
98  return !isInWriteMode();
99  }
100 
101  /**
102  * Returns whether the structure block has been processed already.
103  *
104  * The structure block is read immediately when opening a file in read
105  * mode, and written when calling `writeTimestepBlock` for the first
106  * time, or destroying an instance in write mode.
107  */
109  {
110  return structureBlockProcessed;
111  }
112 
113  /**
114  * Sets the size of the primary simulation volume.
115  *
116  * This information is part of the structure block.
117  *
118  * @throw OpenMPCD::InvalidCallException
119  * Throws if the instance is not in write mode.
120  * @throw OpenMPCD::InvalidCallException
121  * Throws if the structure block has already been written.
122  *
123  * @param[in] x The size along the Cartesian `x` axis.
124  * @param[in] y The size along the Cartesian `y` axis.
125  * @param[in] z The size along the Cartesian `z` axis.
126  */
128  const FP& x, const FP& y, const FP& z);
129 
130  /**
131  * Returns whether the size of the primary simulation volume is set.
132  */
134  {
135  return primarySimulationVolumeSizeSet;
136  }
137 
138  /**
139  * Returns the size of the primary simulation volume.
140  *
141  * The returned vector holds the Cartesian coordinates.
142  *
143  * @throw OpenMPCD::InvalidCallException
144  * Throws if `!primarySimulationVolumeSizeIsSet()`.
145  */
147  {
150 
151  return primarySimulationVolumeSize;
152  }
153 
154  /**
155  * Declares a number of atoms.
156  *
157  * @throw OpenMPCD::InvalidCallException
158  * Throws if the instance is not in write mode.
159  * @throw OpenMPCD::InvalidCallException
160  * Throws if the structure block has already been written.
161  *
162  * @param[in] count The number of atoms to declare;
163  * if it is 0, nothing happens.
164  *
165  * @return Returns the ID of the first declared atom as the first value,
166  * and the ID of the last declared atom as the second value.
167  * If `count == 0`, the pair `{0, 0}` is returned.
168  */
169  const std::pair<std::size_t, std::size_t>
170  declareAtoms(const std::size_t count);
171 
172  /**
173  * Declares a number of atoms of the same kind.
174  *
175  * @throw OpenMPCD::InvalidArgumentException
176  * Throws if the arguments violate the conditions outlined.
177  *
178  * @param[in] count The number of atoms to declare;
179  * if it is 0, nothing happens.
180  * @param[in] radius The radius of the atoms, which must be
181  * greater than or equal to 0, or -1 for default.
182  * @param[in] name The name of the atoms, as a string without
183  * whitespace and of length greater than 0 but
184  * less than or equal to 16, or empty for default.
185  * @param[in] type The type of the atoms, as a string without
186  * whitespace and of length greater than 0 but
187  * less than or equal to 16, or empty for default.
188  *
189  * @return Returns the ID of the first declared atom as the first value,
190  * and the ID of the last declared atom as the second value.
191  * If `count == 0`, the pair `{0, 0}` is returned.
192  */
193  const std::pair<std::size_t, std::size_t> declareAtoms(
194  const std::size_t count, const FP radius,
195  const std::string& name, const std::string& type);
196 
197  /**
198  * Returns the number of atoms that have been declared.
199  */
200  std::size_t getNumberOfAtoms() const
201  {
202  if(atomRanges.empty())
203  return 0;
204 
205  return atomRanges.back().last + 1;
206  }
207 
208  /**
209  * Returns whether the given number is a valid atom ID, i.e.
210  * whether `atomID < getNumberOfAtoms()`.
211  *
212  * @param[in] atomID The atom ID to check.
213  */
214  bool isValidAtomID(const std::size_t atomID) const
215  {
216  return atomID < getNumberOfAtoms();
217  }
218 
219  /**
220  * Returns the properties of the given `atomID`.
221  *
222  * @throw OpenMPCD::OutOfBoundsException
223  * Throws if `!isValidAtomID(atomID)`.
224  *
225  * @param[in] atomID The ID of the atom in question.
226  */
227  const AtomProperties& getAtomProperties(const std::size_t atomID) const;
228 
229  /**
230  * Declares a bond between the two given atoms.
231  *
232  * @throw OpenMPCD::InvalidCallException
233  * Throws if the instance is not in write mode.
234  * @throw OpenMPCD::InvalidCallException
235  * Throws if the structure block has already been written.
236  * @throw OpenMPCD::OutOfBoundsException
237  * Throws if `!isValidAtomID(atom1)` or `!isValidAtomID(atom2)`.
238  * @throw OpenMPCD::InvalidArgumentException
239  * Throws if `atom1 == atom2`.
240  * @throw OpenMPCD::InvalidArgumentException
241  * Throws if a bond between those atoms exists already.
242  *
243  * @param[in] atom1 The ID of the first atom.
244  * @param[in] atom2 The ID of the second atom.
245  */
246  void declareBond(std::size_t atom1, std::size_t atom2);
247 
248  /**
249  * Returns the set of bonds between atoms.
250  *
251  * Each entry `bond` of the returned value denotes a bond between the
252  * atoms with the IDs `bond.first` and `bond.second`, where
253  * `bond.first < bond.second`.
254  */
255  const std::set<std::pair<std::size_t, std::size_t> >& getBonds() const
256  {
257  return bonds;
258  }
259 
260  /**
261  * Returns whether the two given atoms share a bond.
262  *
263  * The order of the arguments does not influence the returned value.
264  *
265  * @throw OpenMPCD::OutOfBoundsException
266  * Throws if `!isValidAtomID(atom1)` or `!isValidAtomID(atom2)`.
267  * @throw OpenMPCD::InvalidArgumentException
268  * Throws if `atom1 == atom2`.
269  *
270  * @param[in] atom1 The ID of the first atom.
271  * @param[in] atom2 The ID of the second atom.
272  */
273  bool hasBond(std::size_t atom1, std::size_t atom2) const;
274 
275  /**
276  * Starts a new timestep block, and writes the atom coordinates given.
277  *
278  * Calling this function will trigger writing of the structure block.
279  *
280  * @throw OpenMPCD::InvalidCallException
281  * Throws if the instance is not in write mode.
282  * @throw OpenMPCD::NULLPointerException
283  * Throws if `positions` is `nullptr`.
284  *
285  * @param[in] positions An array holding the positions of the
286  * `getNumberOfAtoms()` atoms, in the following
287  * format: First, there are the `x`, `y`, and `z`
288  * coordinates of atom `0`, in that order; then,
289  * the coordinates of atom `1` follow, etc.
290  * @param[in] velocities
291  * An array holding the velocities of the
292  * `getNumberOfAtoms()` atoms, in the following
293  * format: First, there are the `x`, `y`, and `z`
294  * velocities of atom `0`, in that order; then,
295  * the velocities of atom `1` follow, etc.
296  * If `nullptr` is passed, no velocities are
297  * written to the snapshot file.
298  */
299  void writeTimestepBlock(
300  const FP* const positions,
301  const FP* const velocities = NULL);
302 
303  /**
304  * Reads the next timestep block.
305  *
306  * @throw OpenMPCD::InvalidCallException
307  * Throws if the instance is not in read mode.
308  * @throw OpenMPCD::UnimplementedException
309  * Throws if the timestep block is not in ordered format.
310  * @throw OpenMPCD::MalformedFileException
311  * Throws if in the timestep block read, some atoms contain
312  * velocity information, while others do not.
313  * @throw OpenMPCD::MalformedFileException
314  * Throws if the timestep block is malformed or contains fewer
315  * atoms than `getNumberOfAtoms()`.
316  *
317  * @param[out] positions An array capable of holding the positions of
318  * holding `3*getNumberOfAtoms()` elements, or
319  * `nullptr` if the positions are not desired. If
320  * not `nullptr`, the array will be populated in
321  * the following format: First, there are the `x`,
322  * `y`, and `z` coordinates of atom `0`, in that
323  * order; then, the coordinates of atom `1`
324  * follow, etc.
325  * @param[out] velocities
326  * An array capable of holding the velocities of
327  * holding `3*getNumberOfAtoms()` elements, or
328  * `nullptr` if the velocities are not desired. If
329  * not `nullptr`, the array will be populated in
330  * the following format: First, there are the `x`,
331  * `y`, and `z` velocities of atom `0`, in that
332  * order; then, the coordinates of atom `1`
333  * follow, etc.
334  * If no velocities are stored in the snapshot
335  * file, the given buffer's contents are left
336  * unchanged.
337  * @param[out] velocitiesEncountered
338  * If not `nullptr`, stores whether the timestep
339  * block read contained velocity information.
340  *
341  * @return Returns true if a complete timestep block has been read.
342  */
343  bool readTimestepBlock(
344  FP* const positions,
345  FP* const velocities = NULL,
346  bool* const velocitiesEncountered = NULL);
347 
348 
349  private:
350  /**
351  * Holds information about a range of atoms.
352  */
353  struct AtomRange
354  {
355  std::size_t first; ///< The first atom in this range.
356  std::size_t last; ///< The last atom in this range.
357  AtomProperties properties; ///< The atom properties of this range.
358  };
359 
360 
361  private:
362  /**
363  * Throws if the instance is not in write mode.
364  *
365  * @throw OpenMPCD::InvalidCallException
366  * Throws if the instance is not in write mode.
367  */
368  void assertWriteMode() const;
369 
370  /**
371  * Throws if the instance is not in read mode.
372  *
373  * @throw OpenMPCD::InvalidCallException
374  * Throws if the instance is not in read mode.
375  */
376  void assertReadMode() const;
377 
378  /**
379  * Throws if the structure block has already been processed.
380  *
381  * @throw OpenMPCD::InvalidCallException
382  * Throws if the structure block has already been processed.
383  */
384  void assertStructureBlockNotProcessed() const;
385 
386  /**
387  * Writes the structure block to the file.
388  *
389  * This also sets the `structureBlockProcessed` flag.
390  *
391  * @throw OpenMPCD::InvalidCallException
392  * Throws if the instance is not in write mode.
393  * @throw OpenMPCD::InvalidCallException
394  * Throws if the structure block has already been written.
395  */
396  void writeStructureBlock();
397 
398  /**
399  * Reads the snapshot file's structure block.
400  *
401  * @throw OpenMPCD::InvalidCallException
402  * Throws if the instance is not in read mode.
403  * @throw OpenMPCD::MalformedFileException
404  * Throws if the VTF file is malformed.
405  */
406  void readStructureBlock();
407 
408  /**
409  * Reads a `unitcell line`.
410  *
411  * @throw OpenMPCD::InvalidCallException
412  * Throws if the instance is not in read mode.
413  *
414  * @param[in] line The line to read.
415  */
416  void readUnitcellLine(const std::string& line);
417 
418  /**
419  * Writes out the `atom lines`.
420  *
421  * @throw OpenMPCD::InvalidCallException
422  * Throws if the instance is not in write mode.
423  * @throw OpenMPCD::InvalidCallException
424  * Throws if the structure block has already been written.
425  */
426  void writeAtomLines();
427 
428  /**
429  * Reads an `atom line`.
430  *
431  * @throw OpenMPCD::InvalidCallException
432  * Throws if the instance is not in read mode.
433  * @throw OpenMPCD::MalformedFileException
434  * Throws if the given `line_` is malformed.
435  *
436  * @param[in] line_ The line to read.
437  */
438  void readAtomLine(const std::string& line_);
439 
440  /**
441  * Saves the given atom range.
442  * @param[in] parameters The atom range to save.
443  */
444  void setAtomRange(const AtomRange& range);
445 
446  /**
447  * Throws if the atom ranges are not contiguous and starting at 0.
448  *
449  * @throw OpenMPCD::Exception
450  * Throws if the atom ranges are not contiguouos
451  * and starting at 0.
452  */
453  void assertAtomRangesContiguous() const;
454 
455  /**
456  * Writes out the `bond lines`.
457  *
458  * @throw OpenMPCD::InvalidCallException
459  * Throws if the instance is not in write mode.
460  * @throw OpenMPCD::InvalidCallException
461  * Throws if the structure block has already been written.
462  */
463  void writeBondLines();
464 
465  /**
466  * Reads a `bond line`.
467  *
468  * @throw OpenMPCD::InvalidCallException
469  * Throws if the instance is not in read mode.
470  * @throw OpenMPCD::MalformedFileException
471  * Throws if the given `line_` is malformed.
472  *
473  * @param[in] line_ The line to read.
474  */
475  void readBondLine(const std::string& line_);
476 
477  /**
478  * Returns the next line in the file.
479  *
480  * Leading whitespace will be removed.
481  *
482  * @throw OpenMPCD::InvalidCallException
483  * Throws if the instance is not in read mode.
484  *
485  * @param[in] extract Whether to extract the line from the file stream.
486  */
487  const std::string getLine(const bool extract);
488 
489  /**
490  * Returns the given string without leading whitespace.
491  *
492  * @param[in] str The string to strip from leading whitespace.
493  */
494  static const std::string stripLeadingWhitespace(const std::string& str);
495 
496  /**
497  * Returns the numeric value contained in the given string.
498  *
499  * @throw OpenMPCD::MalformedFileException
500  * Throws if the cast failed.
501  *
502  * @tparam T The type of the numeric value expected.
503  *
504  * @param[in] str The string to cast.
505  */
506  template<typename T> static T lexicalCast(const std::string& str)
507  {
508  try
509  {
510  return boost::lexical_cast<T>(str);
511  }
512  catch(const boost::bad_lexical_cast&)
513  {
514  OPENMPCD_THROW(MalformedFileException, "Lexical cast failed.");
515  }
516  }
517 
518 
519  private:
520  std::fstream file; ///< The underlying file object.
521  bool writeModeFlag; ///< Whether the instance is in write mode.
522  bool structureBlockProcessed; /**< Whether the structure block has
523  already been processed. */
524 
525  bool primarySimulationVolumeSizeSet; /**< Whether information about
526  the size of the primary
527  simulation volume has been
528  supplied. */
529  Vector3D<FP> primarySimulationVolumeSize; /**< The size of the primary
530  simulation volume. */
531 
532  AtomProperties defaultAtomProperties;
533  ///< Holds the current default vaues for new atoms.
534  std::list<AtomRange> atomRanges; ///< The ranges of atoms defined.
535 
536  std::set<std::pair<std::size_t, std::size_t> > bonds;
537  /**< The set of bonds. Each entry `bond` denotes a bond between
538  the atoms with the IDs `bond.first` and `bond.second`, where
539  `bond.first < bond.second`. */
540 
541 }; //class VTFSnapshotFile
542 
543 } //namespace OpenMPCD
544 
545 #endif /* OPENMPCD_VTFSNAPSHOTFILE_HPP */
OpenMPCD::VTFSnapshotFile::structureBlockHasBeenProcessed
bool structureBlockHasBeenProcessed() const
Returns whether the structure block has been processed already.
Definition: VTFSnapshotFile.hpp:108
OpenMPCD::VTFSnapshotFile::getPrimarySimulationVolumeSize
const Vector3D< FP > & getPrimarySimulationVolumeSize() const
Returns the size of the primary simulation volume.
Definition: VTFSnapshotFile.hpp:146
OpenMPCD::VTFSnapshotFile::~VTFSnapshotFile
virtual ~VTFSnapshotFile()
The destructor.
Definition: VTFSnapshotFile.cpp:59
OpenMPCD::InvalidCallException
Exception for a forbidden function call.
Definition: Exceptions.hpp:144
Exceptions.hpp
OPENMPCD_THROW
#define OPENMPCD_THROW(ExceptionType, message)
Throws the given ExceptionType, passing the given message along with file and line number information...
Definition: Exceptions.hpp:22
OpenMPCD::Vector3D< FP >
OpenMPCD::VTFSnapshotFile::writeTimestepBlock
void writeTimestepBlock(const FP *const positions, const FP *const velocities=NULL)
Starts a new timestep block, and writes the atom coordinates given.
Definition: VTFSnapshotFile.cpp:190
OpenMPCD::VTFSnapshotFile::getNumberOfAtoms
std::size_t getNumberOfAtoms() const
Returns the number of atoms that have been declared.
Definition: VTFSnapshotFile.hpp:200
OpenMPCD::VTFSnapshotFile::AtomProperties::name
boost::optional< std::string > name
The name of the atom.
Definition: VTFSnapshotFile.hpp:58
OpenMPCD::VTFSnapshotFile::VTFSnapshotFile
VTFSnapshotFile(const std::string &path_)
The constructor.
Definition: VTFSnapshotFile.cpp:19
OpenMPCD::VTFSnapshotFile::declareAtoms
const std::pair< std::size_t, std::size_t > declareAtoms(const std::size_t count)
Declares a number of atoms.
Definition: VTFSnapshotFile.cpp:79
OpenMPCD::VTFSnapshotFile::AtomProperties
Collection of properties of atoms.
Definition: VTFSnapshotFile.hpp:55
OpenMPCD::VTFSnapshotFile::AtomProperties::radius
boost::optional< FP > radius
The radius of the atom.
Definition: VTFSnapshotFile.hpp:57
OpenMPCD::VTFSnapshotFile::getAtomProperties
const AtomProperties & getAtomProperties(const std::size_t atomID) const
Returns the properties of the given atomID.
Definition: VTFSnapshotFile.cpp:138
OpenMPCD::VTFSnapshotFile::declareBond
void declareBond(std::size_t atom1, std::size_t atom2)
Declares a bond between the two given atoms.
Definition: VTFSnapshotFile.cpp:152
OpenMPCD::VTFSnapshotFile::getBonds
const std::set< std::pair< std::size_t, std::size_t > > & getBonds() const
Returns the set of bonds between atoms.
Definition: VTFSnapshotFile.hpp:255
Vector3D.hpp
OpenMPCD::FP
double FP
Default floating point type.
Definition: Types.hpp:13
OpenMPCD::VTFSnapshotFile::readTimestepBlock
bool readTimestepBlock(FP *const positions, FP *const velocities=NULL, bool *const velocitiesEncountered=NULL)
Reads the next timestep block.
Definition: VTFSnapshotFile.cpp:220
Types.hpp
OpenMPCD::VTFSnapshotFile::setPrimarySimulationVolumeSize
void setPrimarySimulationVolumeSize(const FP &x, const FP &y, const FP &z)
Sets the size of the primary simulation volume.
Definition: VTFSnapshotFile.cpp:65
OpenMPCD::VTFSnapshotFile::isInWriteMode
bool isInWriteMode() const
Returns whether the instance is in write mode.
Definition: VTFSnapshotFile.hpp:88
OpenMPCD::VTFSnapshotFile
Representation of a simulation snapshot file in the VTF format.
Definition: VTFSnapshotFile.hpp:49
OpenMPCD::SnapshotFile
Base class for files that contain one or more simulation snapshots.
Definition: SnapshotFile.hpp:15
OpenMPCD::VTFSnapshotFile::primarySimulationVolumeSizeIsSet
bool primarySimulationVolumeSizeIsSet() const
Returns whether the size of the primary simulation volume is set.
Definition: VTFSnapshotFile.hpp:133
OpenMPCD::VTFSnapshotFile::hasBond
bool hasBond(std::size_t atom1, std::size_t atom2) const
Returns whether the two given atoms share a bond.
Definition: VTFSnapshotFile.cpp:174
OpenMPCD::VTFSnapshotFile::isValidAtomID
bool isValidAtomID(const std::size_t atomID) const
Returns whether the given number is a valid atom ID, i.e.
Definition: VTFSnapshotFile.hpp:214
OpenMPCD::VTFSnapshotFile::AtomProperties::type
boost::optional< std::string > type
The type of the atom.
Definition: VTFSnapshotFile.hpp:59
SnapshotFile.hpp
OpenMPCD::VTFSnapshotFile::isInReadMode
bool isInReadMode() const
Returns whether the instance is in read mode.
Definition: VTFSnapshotFile.hpp:96