DCD trajectory files
********************

The DCD file is the most compact trajectory file format, which is very
advantageous considering the large size of MD trajectories. It only
stores the coordinates and lattice vectors, so for visualization it
needs to be combined with another file. VMD can read a DCD file in
combination with any single frame file (XYZ, PDB), or with a PSF
topology file (CHARMM).

class DCDTrajectoryFile(filename=None, mode='rb', fileobject=None, ntap=None)

   Class representing a DCD file containing a molecular trajectory

   An instance of this class has the following attributes:

   * "file_object" -- A Python "file" object, referring to the actual
     DCD file

   * "position"    -- The frame to which the cursor is currently
     pointing in the DCD file

   * "mode"        -- Designates whether the file is in read or write
     mode ('rb' or 'wb')

   * "ntap"        -- The number of atoms in the molecular system
     (needs to be constant throughout)

   An "DCDTrajectoryFile" object behaves very similar to a regular
   file object. It has read and write methods ("read_next()" and
   "write_next()") that read and write from/to the position of the
   cursor in the "file_object" attribute. If the file is in read mode,
   an additional method "read_frame()" can be used that moves the
   cursor to any frame in the file and reads from there. The amount of
   information stored in memory is kept to a minimum, as only
   information from the current frame is ever stored.

   Reading and writing to and from the files can be done as follows:

      >>> from scm.plams import DCDTrajectoryFile

      >>> dcd = DCDTrajectoryFile('old.dcd')
      >>> mol = dcd.get_plamsmol()

      >>> dcdout = DCDTrajectoryFile('new.dcd',mode='wb',ntap=dcd.ntap)

      >>> for i in range(dcd.get_length()) :
      >>>     crd,cell = dcd.read_frame(i,molecule=mol)
      >>>     dcdout.write_next(molecule=mol)

   The above script reads information from the DCD file old.dcd into
   the "Molecule" object "mol" in a step-by-step manner. The
   "Molecule" object is then passed to the "write_next()" method of
   the new "DCDTrajectoryFile" object corresponding to the new dcd
   file "new.dcd".

   The exact same result can also be achieved by iterating over the
   instance as a callable

   >>> dcd = DCDTrajectoryFile('old.dcd')
   >>> mol = dcd.get_plamsmol()

   >>> dcdout = DCDTrajectoryFile('new.dcd',mode='wb',ntap=dcd.ntap)

   >>> for crd,cell in dcd(mol) :
   >>>     dcdout.write_next(molecule=mol)

   This procedure requires all coordinate information to be passed to
   and from the "Molecule" object for each frame, which can be time-
   consuming. It is therefore also possible to bypass the "Molecule"
   object when reading through the frames:

      >>> dcd = DCDTrajectoryFile('old.dcd')

      >>> dcdout = DCDTrajectoryFile('new.dcd',mode='wb',ntap=dcd.ntap)

      >>> for crd,cell in dcd :
      >>>     dcdout.write_next(coords=crd,cell=cell)

   __init__(filename=None, mode='rb', fileobject=None, ntap=None)

      Initiates a DCDTrajectoryFile object

      * "filename"   -- The path to the DCD file

      * "mode"       -- The mode in which to open the DCD file ('rb'
        or 'wb')

      * "fileobject" -- Optionally, a file object can be passed
        instead (filename needs to be set to None)

      * "ntap"       -- If the file is in write mode, the number of
        atoms needs to be passed here

   set_byteorder(byteorder)

      Specifies wether the file to be read from or written to is
      little endian or big endian

      * "byteorder" -- Can be either '@', '<', or '>', denoting native
        endian, little endian, or big endian

   read_next(molecule=None, read=True)

      Reads coordinates and lattice info from the current position of
      the cursor and returns it

      * "molecule" -- "Molecule" object in which the new data needs to
        be stored

      * "read"     -- If set to False the cursor will move to the next
        frame without reading

   write_next(coords=None, molecule=None, cell=[0.0, 0.0, 0.0], conect=None)

      Write frame to next position in trajectory file

      * "coords"   -- A list or numpy array of ("ntap",3) containing
        the system coordinates

      * "molecule" -- A molecule object to read the molecular data
        from

      * "cell"     -- A set of lattice vectors or cell diameters

      * "conect"   -- A dictionary containing connectivity info (not
        used)

      Note:

        Either "coords" or "molecule" are mandatory arguments

   __call__(molecule=None, read=True)

      Magic method that makes an instance of this class into a
      callable

   _move_cursor_to_append_pos()

      Get file ready to append

   _set_fileobject(filename, fileobject, mode)

      Set the file object and mode (read/write)

   close()

      Close the file

   property connection_table

      Symmetrize the connection table and remove bond orders

   get_elements()

      Get the elements attribute

   get_length()

      Get the number of frames in the file

   get_plamsmol()

      Extracts a PLAMS molecule object from the XYZ trajectory file

   property molecule

      Returns the current molecule, which exists only when the object
      is used as an iterator

   read_frame(frame, molecule=None)

      Reads the relevant info from frame "frame" and returns it, or
      stores it in "molecule"

      * "frame"    -- The frame number to be read from the file

      * "molecule" -- "Molecule" object in which the new coordinates
        need to be stored

   read_last_frame(molecule=None)

      Reads the last frame from the file

   rewind(nframes=None)

      Rewind the file either by "nframes" or to the first frame

      * "nframes" -- The number of frames to rewind

   set_elements(elements)

      Sets the elements attribute (needed in write mode).

      * "elements" -- A list containing the element symbol of each
        atom
