Source code for parmed.namd.namdbinfiles

"""
This module contains classes for reading and writing (single frame) NAMD binary
files.  The main functionality is currently aimed at manipulation rather than
analysis.
"""
from __future__ import division

from parmed import unit as u
from struct import unpack, pack

import numpy as np


[docs]class NamdBinFile(object): """From the NAMD manual: NAMD uses a trivial double-precision binary file format for coordinates, velocities, and forces ... The file consists of the atom count as a 32-bit integer followed by all three position or velocity components for each atom as 64-bit double-precision floating point ... The main attributes are the number of atom entries (natom) and a (flat) numpy array of size 3*natom (values). The meaning of "values" is effectively arbitrary, but for convenience derived classes are provided which alias the values to more descriptive names (e.g. "coordinates"). See Also -------- :class:`NamdBinCoor` :class:`NamdBinVel` """ _SCALE_FACTOR = 1.0 def __init__(self, values=[]): self._values = np.asarray(values,np.float64) * self._SCALE_FACTOR @property def natom(self): """The current number of atom entries.""" return int(self._values.size / 3)
[docs] @classmethod def read(cls, fname): """Return an object from the values in a NAMD binary file.""" infile = open(fname,'rb') natoms = int(unpack('i',infile.read(4))[0]) values = [unpack('d',infile.read(8))[0] for n in range(3*natoms)] infile.close() return cls(values)
[docs] def write(self, fname): """Write the current attributes to a file.""" outfile = open(fname,'wb') outfile.write(pack('i',self.natom)) for x in self._values / self._SCALE_FACTOR: outfile.write(pack('d',x)) outfile.close()
[docs] def delatoms(self, indices): """Delete entries corresponding to the given atom indices.""" del_indices = np.atleast_1d(np.asarray(indices,np.int32)) mask = np.ones(self.natom,np.bool) mask[del_indices] = False newvalues = np.zeros(3*(self.natom - del_indices.size),np.float64) newvalues += self._values.reshape((self.natom,3))[mask].flatten() self._values = newvalues
[docs] def insertatoms(self, start_index, natoms, values=None): """Insert space for natom entries beginning at start_index. If specified, give them the provided values, otherwise set them to zero. """ if values is not None: values = np.asarray(values) assert values.size == 3*natoms else: values = np.zeros(3*natoms) hinge = 3*start_index newvalues = np.concatenate( (self._values[:hinge],values,self._values[hinge:]) ) self._values = newvalues
[docs] def copyatoms(self, start_index, natoms): """Convenience function, same as insertatoms() but set 'values' to be the same as the previous natoms' values (i.e. make a copy of them). """ values = self._values[3*(start_index-natoms):3*start_index] self.insertatoms(start_index,natoms,values)
[docs]class NamdBinCoor(NamdBinFile): """ Class to read or write NAMD "bincoordinates" files. """ @property def coordinates(self): return self._values.reshape((-1, self.natom, 3)) @coordinates.setter def coordinates(self, value): if u.is_quantity(value): value = value.value_in_unit(u.angstroms) self._values = np.array(value).flatten()
[docs]class NamdBinVel(NamdBinFile): """ Class to read or write NAMD "binvelocities" files. """ _SCALE_FACTOR = 20.45482706 @property def velocities(self): return self._values.reshape((-1, self.natom, 3)) @velocities.setter def velocities(self, value): if u.is_quantity(value): value = value.value_in_unit(u.angstroms/u.picosecond) self._values = np.array(value).flatten()