-
Notifications
You must be signed in to change notification settings - Fork 835
/
xcrysden.py
106 lines (84 loc) · 3.55 KB
/
xcrysden.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
"""Support for reading XCrysDen files."""
from __future__ import annotations
from pymatgen.core import Element, Structure
__author__ = "Matteo Giantomassi"
__copyright__ = "Copyright 2013, The Materials Project"
__version__ = "0.1"
__maintainer__ = "Matteo Giantomassi"
class XSF:
"""Class for parsing XCrysden files."""
def __init__(self, structure: Structure):
"""
Args:
structure (Structure): Structure object.
"""
self.structure = structure
def to_str(self, atom_symbol=True):
"""
Returns a string with the structure in XSF format
See http://www.xcrysden.org/doc/XSF.html.
Args:
atom_symbol (bool): Uses atom symbol instead of atomic number. Defaults to True.
"""
lines = []
app = lines.append
app("CRYSTAL")
app("# Primitive lattice vectors in Angstrom")
app("PRIMVEC")
cell = self.structure.lattice.matrix
for i in range(3):
app(f" {cell[i][0]:.14f} {cell[i][1]:.14f} {cell[i][2]:.14f}")
cart_coords = self.structure.cart_coords
app("# Cartesian coordinates in Angstrom.")
app("PRIMCOORD")
app(f" {len(cart_coords)} 1")
for site, coord in zip(self.structure, cart_coords):
sp = site.specie.symbol if atom_symbol else f"{site.specie.Z}"
x, y, z = coord
app(f"{sp} {x:20.14f} {y:20.14f} {z:20.14f}")
return "\n".join(lines)
@classmethod
def from_str(cls, input_string, cls_=None):
"""
Initialize a `Structure` object from a string with data in XSF format.
Args:
input_string: String with the structure in XSF format.
See http://www.xcrysden.org/doc/XSF.html
cls_: Structure class to be created. default: pymatgen structure
"""
# CRYSTAL see (1)
# these are primitive lattice vectors (in Angstroms)
# PRIMVEC
# 0.0000000 2.7100000 2.7100000 see (2)
# 2.7100000 0.0000000 2.7100000
# 2.7100000 2.7100000 0.0000000
# these are conventional lattice vectors (in Angstroms)
# CONVVEC
# 5.4200000 0.0000000 0.0000000 see (3)
# 0.0000000 5.4200000 0.0000000
# 0.0000000 0.0000000 5.4200000
# these are atomic coordinates in a primitive unit cell (in Angstroms)
# PRIMCOORD
# 2 1 see (4)
# 16 0.0000000 0.0000000 0.0000000 see (5)
# 30 1.3550000 -1.3550000 -1.3550000
lattice, coords, species = [], [], []
lines = input_string.splitlines()
for i, line in enumerate(lines):
if "PRIMVEC" in line:
for j in range(i + 1, i + 4):
lattice.append([float(c) for c in lines[j].split()])
if "PRIMCOORD" in line:
num_sites = int(lines[i + 1].split()[0])
for j in range(i + 2, i + 2 + num_sites):
tokens = lines[j].split()
Z = Element(tokens[0]).Z if tokens[0].isalpha() else int(tokens[0])
species.append(Z)
coords.append([float(j) for j in tokens[1:4]])
break
else:
raise ValueError("Invalid XSF data")
if cls_ is None:
cls_ = Structure
s = cls_(lattice, species, coords, coords_are_cartesian=True)
return XSF(s)