Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import numpy as np
3import ase
4from ase.data import chemical_symbols
5from ase.utils import reader, writer
8cfg_default_fields = np.array(['positions', 'momenta', 'numbers', 'magmoms'])
11@writer
12def write_cfg(fd, atoms):
13 """Write atomic configuration to a CFG-file (native AtomEye format).
14 See: http://mt.seas.upenn.edu/Archive/Graphics/A/
15 """
17 fd.write('Number of particles = %i\n' % len(atoms))
18 fd.write('A = 1.0 Angstrom\n')
19 cell = atoms.get_cell(complete=True)
20 for i in range(3):
21 for j in range(3):
22 fd.write('H0(%1.1i,%1.1i) = %f A\n' % (i + 1, j + 1, cell[i, j]))
24 entry_count = 3
25 for x in atoms.arrays.keys():
26 if x not in cfg_default_fields:
27 if len(atoms.get_array(x).shape) == 1:
28 entry_count += 1
29 else:
30 entry_count += atoms.get_array(x).shape[1]
32 vels = atoms.get_velocities()
33 if isinstance(vels, np.ndarray):
34 entry_count += 3
35 else:
36 fd.write('.NO_VELOCITY.\n')
38 fd.write('entry_count = %i\n' % entry_count)
40 i = 0
41 for name, aux in atoms.arrays.items():
42 if name not in cfg_default_fields:
43 if len(aux.shape) == 1:
44 fd.write('auxiliary[%i] = %s [a.u.]\n' % (i, name))
45 i += 1
46 else:
47 if aux.shape[1] == 3:
48 for j in range(3):
49 fd.write('auxiliary[%i] = %s_%s [a.u.]\n' %
50 (i, name, chr(ord('x') + j)))
51 i += 1
53 else:
54 for j in range(aux.shape[1]):
55 fd.write('auxiliary[%i] = %s_%1.1i [a.u.]\n' %
56 (i, name, j))
57 i += 1
59 # Distinct elements
60 spos = atoms.get_scaled_positions()
61 for i in atoms:
62 el = i.symbol
64 fd.write('%f\n' % ase.data.atomic_masses[chemical_symbols.index(el)])
65 fd.write('%s\n' % el)
67 x, y, z = spos[i.index, :]
68 s = '%e %e %e ' % (x, y, z)
70 if isinstance(vels, np.ndarray):
71 vx, vy, vz = vels[i.index, :]
72 s = s + ' %e %e %e ' % (vx, vy, vz)
74 for name, aux in atoms.arrays.items():
75 if name not in cfg_default_fields:
76 if len(aux.shape) == 1:
77 s += ' %e' % aux[i.index]
78 else:
79 s += (aux.shape[1] * ' %e') % tuple(aux[i.index].tolist())
81 fd.write('%s\n' % s)
84default_color = {
85 'H': [0.800, 0.800, 0.800],
86 'C': [0.350, 0.350, 0.350],
87 'O': [0.800, 0.200, 0.200]}
89default_radius = {'H': 0.435, 'C': 0.655, 'O': 0.730}
92def write_clr(fd, atoms):
93 """Write extra color and radius code to a CLR-file (for use with AtomEye).
94 Hit F12 in AtomEye to use.
95 See: http://mt.seas.upenn.edu/Archive/Graphics/A/
96 """
97 color = None
98 radius = None
99 if atoms.has('color'):
100 color = atoms.get_array('color')
101 if atoms.has('radius'):
102 radius = atoms.get_array('radius')
104 if color is None:
105 color = np.zeros([len(atoms), 3], dtype=float)
106 for a in atoms:
107 color[a.index, :] = default_color[a.symbol]
109 if radius is None:
110 radius = np.zeros(len(atoms), dtype=float)
111 for a in atoms:
112 radius[a.index] = default_radius[a.symbol]
114 radius.shape = (-1, 1)
116 for c1, c2, c3, r in np.append(color, radius, axis=1):
117 fd.write('%f %f %f %f\n' % (c1, c2, c3, r))
120@reader
121def read_cfg(fd):
122 """Read atomic configuration from a CFG-file (native AtomEye format).
123 See: http://mt.seas.upenn.edu/Archive/Graphics/A/
124 """
125 nat = None
126 naux = 0
127 aux = None
128 auxstrs = None
130 cell = np.zeros([3, 3])
131 transform = np.eye(3)
132 eta = np.zeros([3, 3])
134 current_atom = 0
135 current_symbol = None
136 current_mass = None
138 L = fd.readline()
139 while L:
140 L = L.strip()
141 if len(L) != 0 and not L.startswith('#'):
142 if L == '.NO_VELOCITY.':
143 vels = None
144 naux += 3
145 else:
146 s = L.split('=')
147 if len(s) == 2:
148 key, value = s
149 key = key.strip()
150 value = [x.strip() for x in value.split()]
151 if key == 'Number of particles':
152 nat = int(value[0])
153 spos = np.zeros([nat, 3])
154 masses = np.zeros(nat)
155 syms = [''] * nat
156 vels = np.zeros([nat, 3])
157 if naux > 0:
158 aux = np.zeros([nat, naux])
159 elif key == 'A':
160 pass # unit = float(value[0])
161 elif key == 'entry_count':
162 naux += int(value[0]) - 6
163 auxstrs = [''] * naux
164 if nat is not None:
165 aux = np.zeros([nat, naux])
166 elif key.startswith('H0('):
167 i, j = [int(x) for x in key[3:-1].split(',')]
168 cell[i - 1, j - 1] = float(value[0])
169 elif key.startswith('Transform('):
170 i, j = [int(x) for x in key[10:-1].split(',')]
171 transform[i - 1, j - 1] = float(value[0])
172 elif key.startswith('eta('):
173 i, j = [int(x) for x in key[4:-1].split(',')]
174 eta[i - 1, j - 1] = float(value[0])
175 elif key.startswith('auxiliary['):
176 i = int(key[10:-1])
177 auxstrs[i] = value[0]
178 else:
179 # Everything else must be particle data.
180 # First check if current line contains an element mass or
181 # name. Then we have an extended XYZ format.
182 s = [x.strip() for x in L.split()]
183 if len(s) == 1:
184 if L in chemical_symbols:
185 current_symbol = L
186 else:
187 current_mass = float(L)
188 elif current_symbol is None and current_mass is None:
189 # Standard CFG format
190 masses[current_atom] = float(s[0])
191 syms[current_atom] = s[1]
192 spos[current_atom, :] = [float(x) for x in s[2:5]]
193 vels[current_atom, :] = [float(x) for x in s[5:8]]
194 current_atom += 1
195 elif (current_symbol is not None and
196 current_mass is not None):
197 # Extended CFG format
198 masses[current_atom] = current_mass
199 syms[current_atom] = current_symbol
200 props = [float(x) for x in s]
201 spos[current_atom, :] = props[0:3]
202 off = 3
203 if vels is not None:
204 off = 6
205 vels[current_atom, :] = props[3:6]
206 aux[current_atom, :] = props[off:]
207 current_atom += 1
208 L = fd.readline()
210 # Sanity check
211 if current_atom != nat:
212 raise RuntimeError('Number of atoms reported for CFG file (={0}) and '
213 'number of atoms actually read (={1}) differ.'
214 .format(nat, current_atom))
216 if np.any(eta != 0):
217 raise NotImplementedError('eta != 0 not yet implemented for CFG '
218 'reader.')
219 cell = np.dot(cell, transform)
221 if vels is None:
222 a = ase.Atoms(
223 symbols=syms,
224 masses=masses,
225 scaled_positions=spos,
226 cell=cell,
227 pbc=True)
228 else:
229 a = ase.Atoms(
230 symbols=syms,
231 masses=masses,
232 scaled_positions=spos,
233 momenta=masses.reshape(-1, 1) * vels,
234 cell=cell,
235 pbc=True)
237 i = 0
238 while i < naux:
239 auxstr = auxstrs[i]
240 if auxstr[-2:] == '_x':
241 a.set_array(auxstr[:-2], aux[:, i:i + 3])
242 i += 3
243 else:
244 a.set_array(auxstr, aux[:, i])
245 i += 1
247 return a