Source code for iodata.formats.gromacs

# IODATA is an input and output module for quantum chemistry.
# Copyright (C) 2011-2019 The IODATA Development Team
#
# This file is part of IODATA.
#
# IODATA is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# IODATA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>
# --
"""GROMACS gro file format.

Files with the gro file extension contain a molecular structure in Gromos87 format.
GROMACS gro files can be used as trajectory by simply concatenating files.

http://manual.gromacs.org/current/reference-manual/file-formats.html#gro

"""


from typing import Tuple, Iterator

import numpy as np

from ..docstrings import (document_load_one, document_load_many)
from ..utils import nanometer, picosecond, LineIterator


__all__ = []


PATTERNS = ['*.gro']


[docs]@document_load_one('GRO', ['atcoords', 'atffparams', 'cellvecs', 'extra', 'title']) def load_one(lit: LineIterator) -> dict: """Do not edit this docstring. It will be overwritten.""" while True: try: data = _helper_read_frame(lit) except StopIteration: break title = data[0] time = data[1] resnums = np.array(data[2]) resnames = np.array(data[3]) attypes = np.array(data[4]) atcoords = data[5] velocities = data[6] cellvecs = data[7] atffparams = { 'attypes': attypes, 'resnames': resnames, 'resnums': resnums } extra = { 'time': time, 'velocities': velocities } result = { 'atcoords': atcoords, 'atffparams': atffparams, 'cellvecs': cellvecs, 'extra': extra, 'title': title, } return result lit.error('Gromacs gro file could not be read.')
[docs]@document_load_many('GRO', ['atcoords', 'atffparams', 'cellvecs', 'extra', 'title']) def load_many(lit: LineIterator) -> Iterator[dict]: """Do not edit this docstring. It will be overwritten.""" # gro files can be used as trajectory by simply concatenating files, # making it trivial to load many frames. while True: try: yield load_one(lit) except IOError: return
def _helper_read_frame(lit: LineIterator) -> Tuple: """Read one frame.""" # Read the first line, get the title and try to get the time. # Time field is optional. line = next(lit) title = line.split(',')[0] if 't=' in line else line[:-1] time = 0.0 if 't=' in line: time = float(line.split('t=')[1]) * picosecond # Read the second line for number of atoms. natoms = int(next(lit)) # Read the atom lines resnums = [] resnames = [] attypes = [] pos = np.zeros((natoms, 3), np.float32) vel = np.zeros((natoms, 3), np.float32) for i in range(natoms): line = next(lit) resnums.append(int(line[:5])) resnames.append(line[5:10].split()[-1]) attypes.append(line[10:15].split()[-1]) words = line[22:].split() pos[i, 0] = float(words[0]) pos[i, 1] = float(words[1]) pos[i, 2] = float(words[2]) vel[i, 0] = float(words[3]) vel[i, 1] = float(words[4]) vel[i, 2] = float(words[5]) pos *= nanometer # atom coordinates are in nanometers vel *= nanometer / picosecond # Read the cell line cell = np.zeros((3, 3), np.float32) words = next(lit).split() if len(words) >= 3: cell[0, 0] = float(words[0]) cell[1, 1] = float(words[1]) cell[2, 2] = float(words[2]) if len(words) == 9: cell[1, 0] = float(words[3]) cell[2, 0] = float(words[4]) cell[0, 1] = float(words[5]) cell[2, 1] = float(words[6]) cell[0, 2] = float(words[7]) cell[1, 2] = float(words[8]) cell *= nanometer return title, time, resnums, resnames, attypes, pos, vel, cell