# Source code for MDAnalysis.coordinates.NAMDBIN

    # -*- Mode: python; tab-width: 4; indent-tabs-mode:nil; coding:utf-8 -*-
    # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
    #
    # MDAnalysis --- https://www.mdanalysis.org
    # Copyright (c) 2006-2017 The MDAnalysis Development Team and contributors
    # (see the file AUTHORS for the full list of names)
    #
    # Released under the Lesser GNU Public Licence, v2.1 or any higher version
    #
    # Please cite your use of MDAnalysis in published work:
    #
    # R. J. Gowers, M. Linke, J. Barnoud, T. J. E. Reddy, M. N. Melo, S. L. Seyler,
    # D. L. Dotson, J. Domanski, S. Buchoux, I. M. Kenney, and O. Beckstein.
    # MDAnalysis: A Python package for the rapid analysis of molecular dynamics
    # simulations. In S. Benthall and S. Rostrup editors, Proceedings of the 15th
    # Python in Science Conference, pages 102-109, Austin, TX, 2016. SciPy.
    # doi: 10.25080/majora-629e541a-00e
    #
    # N. Michaud-Agrawal, E. J. Denning, T. B. Woolf, and O. Beckstein.
    # MDAnalysis: A Toolkit for the Analysis of Molecular Dynamics Simulations.
    # J. Comput. Chem. 32 (2011), 2319--2327, doi:10.1002/jcc.21787
    #

    """NAMDBIN files format --- :mod:`MDAnalysis.coordinates.NAMDBIN`
    ================================================================================

    Read/Write coordinates in `NAMD double-precision binary format`_ (suffix "coor" or "namdbin").

    .. _`NAMD double-precision binary format` : https://www.ks.uiuc.edu/Research/namd/2.10/ug/node11.html#SECTION00061500000000000000

    Classes
    -------

    .. autoclass:: NAMDBINReader
       :members:

    .. autoclass:: NAMDBINWriter
       :members:

    """
    from struct import pack
    import numpy as np

    from . import base
    from ..lib import util

    class NAMDBINReader(base.SingleFrameReaderBase):
        """Reader for NAMD binary coordinate files.

        .. versionadded:: 1.0.0
        """

        format = ["COOR", "NAMDBIN"]
        units = {"length": "Angstrom"}

        def _read_first_frame(self):
            # Read header
            with open(self.filename, "rb") as namdbin:
                self.n_atoms = np.fromfile(namdbin, dtype=np.int32, count=1)[0]
                self.ts = self._Timestep(self.n_atoms, **self._ts_kwargs)
                self.ts.frame = 0
                coord_double = np.fromfile(
                    namdbin, dtype=np.float64, count=self.n_atoms * 3
                )
                self.ts._pos[:] = np.array(coord_double, float).reshape(
                    self.n_atoms, 3
                )

        @staticmethod
        def parse_n_atoms(filename, **kwargs):
            with open(filename, "rb") as namdbin:
                n_atoms = np.fromfile(namdbin, dtype=np.int32, count=1)[0]
            return n_atoms

        def Writer(self, filename, **kwargs):
            """Returns a NAMDBINWriter for *filename*.

            Parameters
            ----------
            filename: str
                filename of the output NAMDBIN file

            Returns
            -------
            :class:`NAMDBINWriter`

            """
            return NAMDBINWriter(filename, **kwargs)

    class NAMDBINWriter(base.WriterBase):
        """Writer for NAMD binary coordinate files.

        Note
        ----
        * Does not handle writing to bz2 or gz compressed file types.

        .. versionadded:: 1.0.0
        """

        format = ["COOR", "NAMDBIN"]
        units = {"time": None, "length": "Angstrom"}

        def __init__(self, filename, n_atoms=None, **kwargs):
            """
            Parameters
            ----------
            filename : str or :class:`~MDAnalysis.lib.util.NamedStream`
                 name of the output file or a stream
            n_atoms  : int
                number of atoms for the output coordinate
            """
            self.filename = util.filename(filename)

        def _write_next_frame(self, obj):
            """Write information associated with ``obj`` at current frame into
            trajectory

            Parameters
            ----------
            obj : :class:`~MDAnalysis.core.groups.AtomGroup` or
                  :class:`~MDAnalysis.core.universe.Universe`
                  write coordinate information associated with `obj`

            .. versionchanged:: 1.0.0
               Renamed from `write` to `_write_next_frame`.
            .. versionchanged:: 2.0.0
               Deprecated support for Timestep argument has now been removed.
               Use AtomGroup or Universe as an input instead.
            """
            if hasattr(obj, "atoms"):  # AtomGroup or Universe
                atoms = obj.atoms
                n_atoms = len(atoms)
                coor = atoms.positions.reshape(n_atoms * 3)
            else:
                errmsg = "Input obj is neither an AtomGroup or Universe"
                raise TypeError(errmsg) from None

            with util.openany(self.filename, "wb") as namdbin:
                # Write NUMATOMS
                namdbin.write(pack("i", n_atoms))
                # Write Coordinate
                namdbin.write(pack("{:d}d".format(len(coor)), *coor))