Coverage for /builds/debichem-team/python-ase/ase/io/amber.py: 86.52%
89 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-03-06 04:00 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-03-06 04:00 +0000
1import numpy as np
3import ase.units as units
6def write_amber_coordinates(atoms, filename):
7 from scipy.io import netcdf_file
8 with netcdf_file(filename, 'w', mmap=False) as fout:
9 _write_amber_coordinates(atoms, fout)
12def read_amber_coordinates(filename):
13 from scipy.io import netcdf_file
14 with netcdf_file(filename, 'r', mmap=False) as fin:
15 return _read_amber_coordinates(fin)
18def _write_amber_coordinates(atoms, fout):
19 fout.Conventions = 'AMBERRESTART'
20 fout.ConventionVersion = "1.0"
21 fout.title = 'Ase-generated-amber-restart-file'
22 fout.application = "AMBER"
23 fout.program = "ASE"
24 fout.programVersion = "1.0"
25 fout.createDimension('cell_spatial', 3)
26 fout.createDimension('label', 5)
27 fout.createDimension('cell_angular', 3)
28 fout.createDimension('time', 1)
29 time = fout.createVariable('time', 'd', ('time',))
30 time.units = 'picosecond'
31 time[0] = 0
32 fout.createDimension('spatial', 3)
33 spatial = fout.createVariable('spatial', 'c', ('spatial',))
34 spatial[:] = np.asarray(list('xyz'))
36 natom = len(atoms)
37 fout.createDimension('atom', natom)
38 coordinates = fout.createVariable('coordinates', 'd',
39 ('atom', 'spatial'))
40 coordinates.units = 'angstrom'
41 coordinates[:] = atoms.get_positions()
43 velocities = fout.createVariable('velocities', 'd',
44 ('atom', 'spatial'))
45 velocities.units = 'angstrom/picosecond'
46 # Amber's units of time are 1/20.455 ps
47 # Any other units are ignored in restart files, so these
48 # are the only ones it is safe to print
49 # See: http://ambermd.org/Questions/units.html
50 # Apply conversion factor from ps:
51 velocities.scale_factor = 20.455
52 # get_velocities call returns velocities with units sqrt(eV/u)
53 # so convert to Ang/ps
54 factor = units.fs * 1000 / velocities.scale_factor
55 velocities[:] = atoms.get_velocities() * factor
57 fout.createVariable('cell_angular', 'c', ('cell_angular', 'label'))
59 cell_spatial = fout.createVariable('cell_spatial', 'c', ('cell_spatial',))
60 cell_spatial[:] = ['a', 'b', 'c']
62 cell_lengths = fout.createVariable('cell_lengths', 'd', ('cell_spatial',))
63 cell_lengths.units = 'angstrom'
64 cell_lengths[:] = atoms.cell.lengths()
66 if not atoms.cell.orthorhombic:
67 raise ValueError('Non-orthorhombic cell not supported with amber')
69 cell_angles = fout.createVariable('cell_angles', 'd', ('cell_angular',))
70 cell_angles[:3] = 90.0
71 cell_angles.units = 'degree'
74def _read_amber_coordinates(fin):
75 from ase import Atoms
77 all_coordinates = fin.variables['coordinates'][:]
78 get_last_frame = False
79 if hasattr(all_coordinates, 'ndim'):
80 if all_coordinates.ndim == 3:
81 get_last_frame = True
82 elif hasattr(all_coordinates, 'shape'):
83 if len(all_coordinates.shape) == 3:
84 get_last_frame = True
85 if get_last_frame:
86 all_coordinates = all_coordinates[-1]
88 atoms = Atoms(positions=all_coordinates)
90 if 'velocities' in fin.variables:
91 all_velocities = fin.variables['velocities']
92 if hasattr(all_velocities, 'units'):
93 if all_velocities.units != b'angstrom/picosecond':
94 raise Exception(
95 f'Unrecognised units {all_velocities.units}')
96 if hasattr(all_velocities, 'scale_factor'):
97 scale_factor = all_velocities.scale_factor
98 else:
99 scale_factor = 1.0
100 all_velocities = all_velocities[:] * scale_factor
101 all_velocities = all_velocities / (1000 * units.fs)
102 if get_last_frame:
103 all_velocities = all_velocities[-1]
104 atoms.set_velocities(all_velocities)
105 if 'cell_lengths' in fin.variables:
106 all_abc = fin.variables['cell_lengths']
107 if get_last_frame:
108 all_abc = all_abc[-1]
109 a, b, c = all_abc
110 all_angles = fin.variables['cell_angles']
111 if get_last_frame:
112 all_angles = all_angles[-1]
113 alpha, beta, gamma = all_angles
115 if (all(angle > 89.99 for angle in [alpha, beta, gamma]) and
116 all(angle < 90.01 for angle in [alpha, beta, gamma])):
117 atoms.set_cell(
118 np.array([[a, 0, 0],
119 [0, b, 0],
120 [0, 0, c]]))
121 atoms.set_pbc(True)
122 else:
123 raise NotImplementedError('only rectangular cells are'
124 ' implemented in ASE-AMBER')
126 else:
127 atoms.set_pbc(False)
129 return atoms