forked from fxcoudert/tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
findsym.py
executable file
·138 lines (108 loc) · 4.21 KB
/
findsym.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/env python3
import copy
import os
import numpy as np
import sys
# You need spglib and ASE to be installed. You can hardwire their path here.
# sys.path.append('/opt/spglib-1.6.0/lib/python')
# sys.path.append('/opt/ase-3.8.1.3440')
import ase
import ase.io
import spglib
element_symbols = [
'X',
'H', 'He', # Period 1
'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', # Period 2
'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', # Period 3
'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', # Period 4
'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', # Period 4
'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', # Period 5
'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', # Period 5
'Cs', 'Ba', # Period 6
'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', # Lanthanides
'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', # Lanthanides
'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', # Period 6
'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', # Period 6
'Fr', 'Ra', # Period 7
'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk', # Actinides
'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', # Actinides
'Rf', 'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', # Period 7
'Uut', 'Fl', 'Uup', 'Lv', 'Uus', 'Uuo'] # Period 7
def angle_between(v1, v2):
"""Angle between two vectors, in degrees"""
p = np.dot(v1 / np.linalg.norm(v1), v2 / np.linalg.norm(v2))
return np.rad2deg(np.arccos(np.clip(p, -1.0, 1.0)))
def cellParameters(lattice):
return (np.linalg.norm(lattice[0]),
np.linalg.norm(lattice[1]),
np.linalg.norm(lattice[2]),
angle_between(lattice[1], lattice[2]),
angle_between(lattice[0], lattice[2]),
angle_between(lattice[0], lattice[1]))
def writeCIF(cell, prec, basename):
# Find spacegroup name and number
sg = spglib.get_spacegroup(cell, symprec=prec)
sg, sgid = sg.split(' (')
sgid = sgid.replace(')', '')
# Find detailed info about the refined cell
lattice, scaled_positions, numbers = spglib.refine_cell(cell, prec)
if len(numbers) != len(cell):
# create new cell
ncell = (lattice, scaled_positions, numbers)
else:
ncell = copy.deepcopy(cell)
sym = spglib.get_symmetry(ncell, prec)
uniques = np.unique(sym['equivalent_atoms'])
a, b, c, alpha, beta, gamma = cellParameters(lattice)
f = open((basename + '_' + sgid + '.cif').replace('/', '|'), 'w')
f.write(f'# Symmetrized structure with precision = {prec}\n')
f.write(f'data_{basename}{sg}\n'.replace(' ', '_'))
f.write('_cell_length_a %.7g\n' % a)
f.write('_cell_length_b %.7g\n' % b)
f.write('_cell_length_c %.7g\n' % c)
f.write('_cell_angle_alpha %.7g\n' % alpha)
f.write('_cell_angle_beta %.7g\n' % beta)
f.write('_cell_angle_gamma %.7g\n' % gamma)
f.write("_symmetry_space_group_name_H-M '" + sg + "'\n")
f.write('_symmetry_Int_Tables_number ' + str(sgid) + '\n')
# Write out atomic positions
f.write('''
loop_
_atom_site_label
_atom_site_type_symbol
_atom_site_occupancy
_atom_site_fract_x
_atom_site_fract_y
_atom_site_fract_z
''')
for pos, at in zip(scaled_positions[uniques], numbers[uniques]):
sym = element_symbols[at]
f.write('%s %s 1.0 %.7f %.7f %.7f\n' % (sym, sym, pos[0], pos[1], pos[2]))
f.close()
##############################################
# Main program follows
if len(sys.argv) != 2:
prog = os.path.basename(sys.argv[0])
print(f'Usage: {prog} file.cif')
sys.exit(1)
try:
cell = ase.io.read(sys.argv[1])
except Exception as e:
print('Could not read CIF structure from file: ' + sys.argv[1])
print('Error message is: ' + str(e))
sys.exit(1)
if sys.argv[1][-4:] == '.cif':
basename = sys.argv[1][:-4]
else:
basename = sys.argv[1]
t = [1, 2, 3, 5, 7]
precs = [1e-10, 1e-9, 1e-8, 1e-7, 1e-6] + [i * j for i in [1e-5, 1e-4, 1e-3, 1e-2, 1e-1] for j in t]
old = ''
print('# Tolerance\tSpace group')
for prec in l:
s = spglib.get_spacegroup(cell, symprec=prec)
if s != old:
print(f'{prec}\t\t{s}')
writeCIF(cell, prec, basename)
old = s
sys.exit(0)