Coverage for /builds/ase/ase/ase/io/jsv.py: 83.18%
107 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-08-02 00:12 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-08-02 00:12 +0000
1# fmt: off
3"""
4A module for reading and writing crystal structures from JSV
5See http://www.jcrystal.com/steffenweber/JAVA/JSV/jsv.html
7By Jesper Friis, Jan. 2012
8"""
11import re
13import numpy as np
15import ase
16from ase.geometry import cell_to_cellpar, cellpar_to_cell
17from ase.spacegroup import Spacegroup, crystal
20def read_jsv(f):
21 """Reads a JSV file."""
22 natom = nbond = npoly = 0
23 symbols = []
24 labels = []
25 cellpar = basis = title = bonds = poly = origin = shell_numbers = None
26 spacegroup = 1
28 headline = f.readline().strip()
30 while True:
31 line = f.readline()
32 if not line:
33 break
34 line = line.strip()
35 m = re.match(r'^\[([^]]+)\]\s*(.*)', line)
36 if m is None or not line:
37 continue
38 tag = m.groups()[0].lower()
40 if len(m.groups()) > 1:
41 args = m.groups()[1].split()
42 else:
43 args = []
45 if tag == 'cell':
46 cellpar = [float(x) for x in args]
47 elif tag == 'natom':
48 natom = int(args[0])
49 elif tag == 'nbond':
50 nbond = int(args[0])
51 # optional margin of the bondlengths
52 elif tag == 'npoly':
53 npoly = int(args[0])
54 elif tag == 'space_group':
55 spacegroup = Spacegroup(*tuple(int(x) for x in args))
56 elif tag == 'title':
57 title = m.groups()[1]
58 elif tag == 'atoms':
59 symbols = []
60 basis = np.zeros((natom, 3), dtype=float)
61 shell_numbers = -np.ones((natom, ), dtype=int) # float?
62 for i in range(natom):
63 tokens = f.readline().strip().split()
64 labels.append(tokens[0])
65 symbols.append(ase.data.chemical_symbols[int(tokens[1])])
66 basis[i] = [float(x) for x in tokens[2:5]]
67 if len(tokens) > 5:
68 shell_numbers[i] = float(tokens[5]) # float?
69 elif tag == 'bonds':
70 for _ in range(nbond):
71 f.readline()
72 bonds = NotImplemented
73 elif tag == 'poly':
74 for _ in range(npoly):
75 f.readline()
76 poly = NotImplemented
77 elif tag == 'origin':
78 origin = NotImplemented
79 else:
80 raise ValueError(f'Unknown tag: "{tag}"')
82 if headline == 'asymmetric_unit_cell':
83 atoms = crystal(symbols=symbols,
84 basis=basis,
85 spacegroup=spacegroup,
86 cellpar=cellpar,
87 )
88 elif headline == 'full_unit_cell':
89 atoms = ase.Atoms(symbols=symbols,
90 scaled_positions=basis,
91 cell=cellpar_to_cell(cellpar),
92 )
93 atoms.info['spacegroup'] = Spacegroup(spacegroup)
94 elif headline == 'cartesian_cell':
95 atoms = ase.Atoms(symbols=symbols,
96 positions=basis,
97 cell=cellpar_to_cell(cellpar),
98 )
99 atoms.info['spacegroup'] = Spacegroup(spacegroup)
100 else:
101 raise ValueError(f'Invalid JSV file type: "{headline}"')
103 atoms.info['title'] = title
104 atoms.info['labels'] = labels
105 if bonds is not None:
106 atoms.info['bonds'] = bonds
107 if poly is not None:
108 atoms.info['poly'] = poly
109 if origin is not None:
110 atoms.info['origin'] = origin
111 if shell_numbers is not None:
112 atoms.info['shell_numbers'] = shell_numbers
114 return atoms
117def write_jsv(fd, atoms):
118 """Writes JSV file."""
119 fd.write('asymmetric_unit_cell\n')
121 fd.write('[cell]')
122 for v in cell_to_cellpar(atoms.cell):
123 fd.write(' %g' % v)
124 fd.write('\n')
126 fd.write('[natom] %d\n' % len(atoms))
127 fd.write('[nbond] 0\n') # FIXME
128 fd.write('[npoly] 0\n') # FIXME
130 if 'spacegroup' in atoms.info:
131 sg = Spacegroup(atoms.info['spacegroup'])
132 fd.write('[space_group] %d %d\n' % (sg.no, sg.setting))
133 else:
134 fd.write('[space_group] 1 1\n')
136 fd.write('[title] %s\n' % atoms.info.get('title', 'untitled'))
138 fd.write('\n')
139 fd.write('[atoms]\n')
140 if 'labels' in atoms.info:
141 labels = atoms.info['labels']
142 else:
143 labels = ['%s%d' % (s, i + 1) for i, s in
144 enumerate(atoms.get_chemical_symbols())]
145 numbers = atoms.get_atomic_numbers()
146 scaled = atoms.get_scaled_positions()
147 for label, n, p in zip(labels, numbers, scaled):
148 fd.write('%-4s %2d %9.6f %9.6f %9.6f\n'
149 % (label, n, p[0], p[1], p[2]))
151 fd.write('Label AtomicNumber x y z (repeat natom times)\n')
153 fd.write('\n')
154 fd.write('[bonds]\n')
156 fd.write('\n')
157 fd.write('[poly]\n')
159 fd.write('\n')