|
"""Functions to read and write RuNNer data files.""" |
|
|
|
__all__ = [ |
|
'write_frame_runner', |
|
'read_frame_runner', |
|
] |
|
|
|
import numpy as np |
|
|
|
from .utilities import Frame, register_io |
|
|
|
|
|
@register_io('RuNNer', 'read', 'data') |
|
def read_frame_runner(f_in): |
|
"""Read one frame of the RuNNer format from an open file. |
|
|
|
Arguments: |
|
f_in: open file in the RuNNer format |
|
|
|
Returns: |
|
`Frame` instance or `None` |
|
""" |
|
|
|
|
|
|
|
|
|
|
|
line_begin = f_in.readline() |
|
|
|
|
|
if not line_begin: |
|
return None |
|
|
|
|
|
if line_begin.strip() != 'begin': |
|
raise ValueError |
|
|
|
comment = None |
|
cell = [] |
|
names = [] |
|
positions = [] |
|
forces = [] |
|
energy = None |
|
|
|
for line in f_in: |
|
items = line.split() |
|
tag = items[0] |
|
|
|
if tag == 'comment': |
|
comment = " ".join(items[1:]) |
|
|
|
elif tag == 'lattice': |
|
cell.append([float(item) for item in items[1:]]) |
|
|
|
elif tag == 'atom': |
|
positions.append([float(item) for item in items[1:4]]) |
|
names.append(items[4]) |
|
forces.append([float(item) for item in items[7:10]]) |
|
|
|
|
|
|
|
elif tag == 'energy': |
|
energy = float(items[1]) |
|
|
|
elif tag == 'charge': |
|
pass |
|
|
|
elif tag == 'end': |
|
break |
|
|
|
else: |
|
raise ValueError('Unexpected data in file.') |
|
|
|
if len(names) == 0: |
|
raise ValueError('No atomic data.') |
|
cell = np.array(cell) |
|
if cell.shape != (3, 3) and len(cell) != 0: |
|
raise ValueError('Wrong cell data.') |
|
if len(cell) == 0: |
|
cell = None |
|
positions = np.array(positions) |
|
forces = np.array(forces) |
|
|
|
|
|
frame = Frame(names=names, positions=positions, comment=comment, cell=cell, energy=energy, forces=forces) |
|
|
|
return frame |
|
|
|
|
|
@register_io('RuNNer', 'write', 'data') |
|
def write_frame_runner(f_out, frame): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (frame.positions is None) or (frame.names is None): |
|
raise ValueError('Frame does not contain required properties - atom names and positions.') |
|
|
|
fmt_lattice = 'lattice ' + 3*'{:16.6f}' + '\n' |
|
fmt_one = '{:13.6f}' |
|
fmt_atom = 'atom ' + 3*fmt_one + '{:^6s}' + 5*fmt_one + '\n' |
|
fmt_energy = 'energy ' + fmt_one + '\n' |
|
fmt_charge = 'charge ' + fmt_one + '\n' |
|
|
|
f_out.write('begin\n') |
|
|
|
if frame.comment is not None: |
|
f_out.write('comment ' + frame.comment + '\n') |
|
|
|
if frame.cell is not None: |
|
for lattice_vector in frame.cell: |
|
f_out.write(fmt_lattice.format(*lattice_vector)) |
|
|
|
if frame.forces is not None: |
|
for i, name in enumerate(frame.names): |
|
f_out.write(fmt_atom.format(*frame.positions[i], name, |
|
0.0, 0.0, *frame.forces[i])) |
|
else: |
|
for i, name in enumerate(frame.names): |
|
f_out.write(fmt_atom.format(*frame.positions[i], name, |
|
0.0, 0.0, 0.0, 0.0, 0.0)) |
|
|
|
if frame.energy is None: |
|
energy = 0.0 |
|
else: |
|
energy = frame.energy |
|
f_out.write(fmt_energy.format(energy)) |
|
|
|
f_out.write(fmt_charge.format(0.0)) |
|
|
|
f_out.write('end\n') |
|
|