mgtoolbox-kernel 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mgtoolbox_kernel/__init__.py +0 -0
- mgtoolbox_kernel/io/__init__.py +27 -0
- mgtoolbox_kernel/io/cif.py +158 -0
- mgtoolbox_kernel/io/vasp/__init__.py +0 -0
- mgtoolbox_kernel/io/vasp/poscar.py +132 -0
- mgtoolbox_kernel/kernel/__init__.py +1 -0
- mgtoolbox_kernel/kernel/atom.py +53 -0
- mgtoolbox_kernel/kernel/cell.py +452 -0
- mgtoolbox_kernel/kernel/mgclass.py +8 -0
- mgtoolbox_kernel/kernel/potential.py +81 -0
- mgtoolbox_kernel/kernel/site.py +219 -0
- mgtoolbox_kernel/kernel/structure.py +194 -0
- mgtoolbox_kernel/util/__init__.py +0 -0
- mgtoolbox_kernel/util/base.py +141 -0
- mgtoolbox_kernel-0.1.0.dist-info/METADATA +15 -0
- mgtoolbox_kernel-0.1.0.dist-info/RECORD +18 -0
- mgtoolbox_kernel-0.1.0.dist-info/WHEEL +5 -0
- mgtoolbox_kernel-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
from typing import Dict, Union, List
|
|
2
|
+
import math
|
|
3
|
+
import numpy as np
|
|
4
|
+
from .mgclass import MGobject
|
|
5
|
+
from .atom import Atom
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Site(MGobject):
|
|
9
|
+
"""
|
|
10
|
+
Site 站点类
|
|
11
|
+
用于描述材料结构中的站点
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
object : [type]
|
|
15
|
+
[description]
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
coord: np.ndarray,
|
|
21
|
+
occupier: Dict[Atom, float] = None,
|
|
22
|
+
label: str = "",
|
|
23
|
+
site_type: str = "",
|
|
24
|
+
attributes: Dict = None,
|
|
25
|
+
):
|
|
26
|
+
"""
|
|
27
|
+
__init__ 站点类初始化
|
|
28
|
+
站点类初始化函数
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
coords : np.ndarray
|
|
32
|
+
站点位置分数坐标
|
|
33
|
+
occupier : Dict, optional
|
|
34
|
+
站点包含的原子及占据率信息, by default None
|
|
35
|
+
label: str, optional
|
|
36
|
+
站点标签信息
|
|
37
|
+
label: str, optional
|
|
38
|
+
站点类型信息
|
|
39
|
+
attributes : Dict, optional
|
|
40
|
+
站点类的其它可自定义属性, by default None。 如{"radius":10}
|
|
41
|
+
"""
|
|
42
|
+
if attributes is None:
|
|
43
|
+
super().__init__(attributes={})
|
|
44
|
+
else:
|
|
45
|
+
super().__init__(attributes)
|
|
46
|
+
self.label: str = label
|
|
47
|
+
self.type: str = site_type
|
|
48
|
+
self.coord: np.ndarray = np.array(coord)
|
|
49
|
+
if occupier is None:
|
|
50
|
+
self.occupier: Dict[Atom, float] = {}
|
|
51
|
+
else:
|
|
52
|
+
self.occupier: Dict[Atom, float] = occupier
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def __eq__(self, other: "Site") -> bool:
|
|
56
|
+
# 判断是否同一站点仅比较站点坐标
|
|
57
|
+
return np.all(np.isclose(self.coord, other.coord, rtol=0.001))
|
|
58
|
+
|
|
59
|
+
def __str__(self) -> str:
|
|
60
|
+
site_string = (
|
|
61
|
+
"\n{"
|
|
62
|
+
+ "label:"
|
|
63
|
+
+ self.label
|
|
64
|
+
+ ", type:"
|
|
65
|
+
+ str(self.type)
|
|
66
|
+
+ ", coord:"
|
|
67
|
+
+ str(self.coord)
|
|
68
|
+
+ ", occupier:"
|
|
69
|
+
+ str(self.occupier)
|
|
70
|
+
+ "}"
|
|
71
|
+
)
|
|
72
|
+
return site_string
|
|
73
|
+
|
|
74
|
+
def __repr__(self) -> str:
|
|
75
|
+
return self.__str__()
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def atoms(self) -> list:
|
|
79
|
+
return list(self.occupier.keys())
|
|
80
|
+
|
|
81
|
+
@property
|
|
82
|
+
def atom_symbols(self) -> list:
|
|
83
|
+
return [atom.symbol for atom in self.occupier.keys()]
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def atom_valences(self) -> list:
|
|
87
|
+
return [atom.valence_state for atom in self.occupier.keys()]
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def atom_occupancies(self) -> list:
|
|
91
|
+
return list(self.occupier.values())
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def x(self) -> float:
|
|
95
|
+
return self.coord[0]
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def y(self) -> float:
|
|
99
|
+
return self.coord[1]
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def z(self) -> float:
|
|
103
|
+
return self.coord[2]
|
|
104
|
+
|
|
105
|
+
@x.setter
|
|
106
|
+
def x(self, x: float):
|
|
107
|
+
self.coord[0] = x
|
|
108
|
+
|
|
109
|
+
@y.setter
|
|
110
|
+
def y(self, y: float):
|
|
111
|
+
self.coord[1] = y
|
|
112
|
+
|
|
113
|
+
@z.setter
|
|
114
|
+
def z(self, z: float):
|
|
115
|
+
self.coord[2] = z
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def is_ordered(self):
|
|
119
|
+
"""站点是否有序(满足站点上只包含一个原子且占据率为1.0)
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
bool
|
|
124
|
+
是否有序
|
|
125
|
+
"""
|
|
126
|
+
return len(self.atoms) == 1 and math.isclose(self.atom_occupancies[0], 1.0)
|
|
127
|
+
|
|
128
|
+
def get_element_occupy(self, symbol: str):
|
|
129
|
+
"""_summary_
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
symbol : str
|
|
134
|
+
_description_
|
|
135
|
+
|
|
136
|
+
Returns
|
|
137
|
+
-------
|
|
138
|
+
_type_
|
|
139
|
+
_description_
|
|
140
|
+
"""
|
|
141
|
+
for atom, occupy in self.occupier.items():
|
|
142
|
+
if atom.symbol == symbol:
|
|
143
|
+
return occupy
|
|
144
|
+
|
|
145
|
+
def assign_occupier(self, atom: Atom, occupy: float = 1.0):
|
|
146
|
+
"""
|
|
147
|
+
assign_occupier 设置站点包含的原子信息
|
|
148
|
+
|
|
149
|
+
设置站点包含的原子,如原子类型,占有率。
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
atom : Atom
|
|
154
|
+
[添加的原子类型]
|
|
155
|
+
occupy : float, optional
|
|
156
|
+
[占据率], by default 1.0
|
|
157
|
+
"""
|
|
158
|
+
if atom in self.atoms: # 若站点上已存在该原子类型,则将占据率求和
|
|
159
|
+
self.occupier[atom] += occupy
|
|
160
|
+
else:
|
|
161
|
+
self.occupier[atom] = occupy
|
|
162
|
+
|
|
163
|
+
def assign_occupier_by_dict(self, occupiper_dict):
|
|
164
|
+
"""_summary_
|
|
165
|
+
|
|
166
|
+
Parameters
|
|
167
|
+
----------
|
|
168
|
+
occupiper_dict : _type_
|
|
169
|
+
_description_
|
|
170
|
+
"""
|
|
171
|
+
for k, v in occupiper_dict.items():
|
|
172
|
+
self.assign_occupier(k, v)
|
|
173
|
+
|
|
174
|
+
def assign_occupier_by_symbol(
|
|
175
|
+
self, symbol: str = "", valence_state: float = 0.0, occupy: float = 1.0
|
|
176
|
+
):
|
|
177
|
+
"""_summary_
|
|
178
|
+
|
|
179
|
+
Parameters
|
|
180
|
+
----------
|
|
181
|
+
symbol : str, optional
|
|
182
|
+
_description_, by default ""
|
|
183
|
+
valence_state : float, optional
|
|
184
|
+
_description_, by default 0.0
|
|
185
|
+
occupy : float, optional
|
|
186
|
+
_description_, by default 1.0
|
|
187
|
+
|
|
188
|
+
Raises
|
|
189
|
+
------
|
|
190
|
+
ValueError
|
|
191
|
+
_description_
|
|
192
|
+
"""
|
|
193
|
+
if len(symbol) > 0:
|
|
194
|
+
atom = Atom(symbol, valence_state)
|
|
195
|
+
if atom not in self.atoms:
|
|
196
|
+
self.assign_occupier(atom, occupy)
|
|
197
|
+
else:
|
|
198
|
+
raise ValueError("Symbol cannot be empty!!!")
|
|
199
|
+
|
|
200
|
+
def get_occupy_sum(self):
|
|
201
|
+
"""_summary_
|
|
202
|
+
|
|
203
|
+
Returns
|
|
204
|
+
-------
|
|
205
|
+
_type_
|
|
206
|
+
_description_
|
|
207
|
+
|
|
208
|
+
Raises
|
|
209
|
+
------
|
|
210
|
+
ValueError
|
|
211
|
+
_description_
|
|
212
|
+
"""
|
|
213
|
+
occu_sum = 0
|
|
214
|
+
for occupy in self.occupier.values():
|
|
215
|
+
occu_sum = occu_sum + occupy
|
|
216
|
+
if occu_sum > 1.0:
|
|
217
|
+
raise ValueError("occupy > 1.0")
|
|
218
|
+
return occu_sum
|
|
219
|
+
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
@File : structure.py
|
|
4
|
+
@Time : 2021/04/30 15:49:14
|
|
5
|
+
@Author : 何冰
|
|
6
|
+
@Email : shhebing@qq.com
|
|
7
|
+
@WebSite : https://mgtoolbox.cn
|
|
8
|
+
@Desc : 材料结构相关类。
|
|
9
|
+
"""
|
|
10
|
+
import re
|
|
11
|
+
from typing import Dict, List, Union
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
import scipy.spatial
|
|
16
|
+
from mgtoolbox_kernel.io import read_structure_file, read_structure_data
|
|
17
|
+
from .mgclass import MGobject
|
|
18
|
+
from .atom import Atom
|
|
19
|
+
from .cell import Cell
|
|
20
|
+
from .site import Site
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Structure(MGobject):
|
|
24
|
+
def __init__(self, sites: List[Site], cell: Cell, attributes=None):
|
|
25
|
+
if attributes is None:
|
|
26
|
+
attributes = {}
|
|
27
|
+
super().__init__(attributes)
|
|
28
|
+
self.sites: List[Site] = sites
|
|
29
|
+
self.cell: Cell = cell
|
|
30
|
+
|
|
31
|
+
def __repr__(self) -> str:
|
|
32
|
+
sstring = str({"cell": self.cell, "sites": self.sites})
|
|
33
|
+
return sstring
|
|
34
|
+
|
|
35
|
+
def add_site(self, site: Site):
|
|
36
|
+
self.sites.append(site)
|
|
37
|
+
|
|
38
|
+
def add_sites(self, sites: List[Site]):
|
|
39
|
+
self.sites += sites
|
|
40
|
+
|
|
41
|
+
def remove_sites(self, sites: List[Site]):
|
|
42
|
+
for site in sites:
|
|
43
|
+
self.sites.remove(site)
|
|
44
|
+
|
|
45
|
+
def set_cell(self, cell: Cell):
|
|
46
|
+
self.cell = cell
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def is_ordered(self):
|
|
50
|
+
"""是否为有序结构
|
|
51
|
+
|
|
52
|
+
Returns
|
|
53
|
+
-------
|
|
54
|
+
bool
|
|
55
|
+
是否有序
|
|
56
|
+
"""
|
|
57
|
+
return all((site.is_ordered for site in self.sites))
|
|
58
|
+
|
|
59
|
+
@staticmethod
|
|
60
|
+
def from_file(filename: Union[str, Path]) -> Union["Structure", List["Structure"]]:
|
|
61
|
+
structs_mode = read_structure_file(filename)
|
|
62
|
+
structs = []
|
|
63
|
+
for struct_mode in structs_mode:
|
|
64
|
+
struct = Structure.from_struct_model(struct_mode)
|
|
65
|
+
structs.append(struct)
|
|
66
|
+
if len(structs) == 1:
|
|
67
|
+
return structs[0]
|
|
68
|
+
else:
|
|
69
|
+
return structs
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def from_data(file_data: str):
|
|
73
|
+
# 默认cif格式文件数据
|
|
74
|
+
structs_mode = read_structure_data(file_data)
|
|
75
|
+
structs = []
|
|
76
|
+
for struct_mode in structs_mode:
|
|
77
|
+
struct = Structure.from_struct_model(struct_mode)
|
|
78
|
+
structs.append(struct)
|
|
79
|
+
if len(structs) == 1:
|
|
80
|
+
return structs[0]
|
|
81
|
+
else:
|
|
82
|
+
return structs
|
|
83
|
+
|
|
84
|
+
@staticmethod
|
|
85
|
+
def merge_eq_coords(coords):
|
|
86
|
+
Structure.adjust_coords(coords)
|
|
87
|
+
dm = scipy.spatial.distance_matrix(coords, coords)
|
|
88
|
+
type_list = list(range(dm.shape[0]))
|
|
89
|
+
for row in range(dm.shape[0]):
|
|
90
|
+
for col in range(row + 1, dm.shape[1]):
|
|
91
|
+
if dm[row][col] < 0.003:
|
|
92
|
+
type_list[col] = type_list[row]
|
|
93
|
+
unique_ids = set(type_list)
|
|
94
|
+
ucoords = coords[list(unique_ids)]
|
|
95
|
+
return ucoords
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
def adjust_coords(coords):
|
|
99
|
+
"""调整分数坐标值
|
|
100
|
+
使得分数坐标值在0.999-1.001范围的坐标更改为0.0
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
coords : _type_
|
|
104
|
+
_description_
|
|
105
|
+
"""
|
|
106
|
+
abs_value = np.abs(coords - 1.0)
|
|
107
|
+
coords[abs_value < 0.001] = 0.0
|
|
108
|
+
|
|
109
|
+
@staticmethod
|
|
110
|
+
def from_struct_model(struct_mode: Dict):
|
|
111
|
+
lattice_paramteters = struct_mode["lattice_parameters"]
|
|
112
|
+
cell = Cell(
|
|
113
|
+
lattice_paramteters[0],
|
|
114
|
+
lattice_paramteters[1],
|
|
115
|
+
lattice_paramteters[2],
|
|
116
|
+
lattice_paramteters[3],
|
|
117
|
+
lattice_paramteters[4],
|
|
118
|
+
lattice_paramteters[5],
|
|
119
|
+
)
|
|
120
|
+
attributes = struct_mode['attributes']
|
|
121
|
+
sites = []
|
|
122
|
+
for struct_site in struct_mode["sites"]:
|
|
123
|
+
coords = np.mod(
|
|
124
|
+
np.dot(struct_mode["symm_ops"][0], struct_site["coord"])
|
|
125
|
+
+ struct_mode["symm_ops"][1],
|
|
126
|
+
1.0,
|
|
127
|
+
)
|
|
128
|
+
# 合并等价位点中坐标相同位点
|
|
129
|
+
# Merge the points with the same coordinates in the equivalent points
|
|
130
|
+
ucoords = Structure.merge_eq_coords(coords)
|
|
131
|
+
for i, coord in enumerate(ucoords):
|
|
132
|
+
occupier = {}
|
|
133
|
+
for symbol, occupy in struct_site["occupancy"].items():
|
|
134
|
+
if occupy < 0.0:
|
|
135
|
+
raise ValueError("Structure file site occupy value error")
|
|
136
|
+
sym = re.findall(r"[A-Z][a-z]?", symbol)
|
|
137
|
+
if struct_mode["oxidation_state"]:
|
|
138
|
+
atom = Atom(sym[0], struct_mode["oxidation_state"][symbol])
|
|
139
|
+
occupier[atom] = occupy
|
|
140
|
+
else:
|
|
141
|
+
# -16 表示该离子化合价无法确定。
|
|
142
|
+
atom = Atom(sym[0], -16)
|
|
143
|
+
occupier[atom] = occupy
|
|
144
|
+
site = Site(coord, occupier)
|
|
145
|
+
site.label = struct_site["label"] + "_" + str(i)
|
|
146
|
+
site.type = struct_site["site_type"]
|
|
147
|
+
sites.append(site)
|
|
148
|
+
unique_sites = Structure.remove_duplicates_sites(sites)
|
|
149
|
+
return Structure(unique_sites, cell, attributes)
|
|
150
|
+
|
|
151
|
+
@staticmethod
|
|
152
|
+
def remove_duplicates_sites(sites: List[Site]):
|
|
153
|
+
result = []
|
|
154
|
+
for item in sites:
|
|
155
|
+
if item not in result:
|
|
156
|
+
result.append(item)
|
|
157
|
+
else:
|
|
158
|
+
result[result.index(item)].assign_occupier_by_dict(item.occupier)
|
|
159
|
+
return result
|
|
160
|
+
|
|
161
|
+
def write_to_cif(self, filename: str):
|
|
162
|
+
with Path(filename).open("+w") as f:
|
|
163
|
+
f.write(f"data_{Path(filename).stem}\n")
|
|
164
|
+
|
|
165
|
+
f.write("_cell_length_a {}\n".format(self.cell.abc[0]))
|
|
166
|
+
f.write("_cell_length_b {}\n".format(self.cell.abc[1]))
|
|
167
|
+
f.write("_cell_length_c {}\n".format(self.cell.abc[2]))
|
|
168
|
+
|
|
169
|
+
f.write("_cell_angle_alpha {}\n".format(self.cell.angles[0]))
|
|
170
|
+
f.write("_cell_angle_beta {}\n".format(self.cell.angles[1]))
|
|
171
|
+
f.write("_cell_angle_gamma {}\n".format(self.cell.angles[2]))
|
|
172
|
+
|
|
173
|
+
f.write("_symmetry_space_group_name_H-M 'P 1'\n")
|
|
174
|
+
f.write("_symmetry_Int_Tables_number 1\n")
|
|
175
|
+
|
|
176
|
+
f.write("loop_\n")
|
|
177
|
+
f.write("_symmetry_equiv_pos_site_id\n")
|
|
178
|
+
f.write("_symmetry_equiv_pos_as_xyz\n")
|
|
179
|
+
f.write("1 'x, y, z'\n")
|
|
180
|
+
|
|
181
|
+
f.write("loop_\n")
|
|
182
|
+
f.write("_atom_site_label\n")
|
|
183
|
+
f.write("_atom_site_type_symbol\n")
|
|
184
|
+
f.write("_atom_site_fract_x\n")
|
|
185
|
+
f.write("_atom_site_fract_y\n")
|
|
186
|
+
f.write("_atom_site_fract_z\n")
|
|
187
|
+
f.write("_atom_site_occupancy\n")
|
|
188
|
+
for site in self.sites:
|
|
189
|
+
for occupier, occupy in site.occupier.items():
|
|
190
|
+
f.write(
|
|
191
|
+
f"{site.label} {occupier.symbol} {site.x} {site.y} {site.z} {occupy}\n"
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
f.write(f"#End of data_{Path(filename).stem}")
|
|
File without changes
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
import math
|
|
3
|
+
import re
|
|
4
|
+
import numpy as np
|
|
5
|
+
import periodictable as pt
|
|
6
|
+
from typing import Tuple
|
|
7
|
+
|
|
8
|
+
def parse_sitesym(symlist, sep=','):
|
|
9
|
+
"""Parses a sequence of site symmetries in the form used by
|
|
10
|
+
International Tables and returns corresponding rotation and
|
|
11
|
+
translation arrays.
|
|
12
|
+
|
|
13
|
+
Example:
|
|
14
|
+
|
|
15
|
+
>>> symlist = [
|
|
16
|
+
... 'x,y,z',
|
|
17
|
+
... '-y+1/2,x+1/2,z',
|
|
18
|
+
... '-y,-x,-z',
|
|
19
|
+
... ]
|
|
20
|
+
>>> rot, trans = parse_sitesym(symlist)
|
|
21
|
+
>>> rot
|
|
22
|
+
array([[[ 1, 0, 0],
|
|
23
|
+
[ 0, 1, 0],
|
|
24
|
+
[ 0, 0, 1]],
|
|
25
|
+
<BLANKLINE>
|
|
26
|
+
[[ 0, -1, 0],
|
|
27
|
+
[ 1, 0, 0],
|
|
28
|
+
[ 0, 0, 1]],
|
|
29
|
+
<BLANKLINE>
|
|
30
|
+
[[ 0, -1, 0],
|
|
31
|
+
[-1, 0, 0],
|
|
32
|
+
[ 0, 0, -1]]])
|
|
33
|
+
>>> trans
|
|
34
|
+
array([[ 0. , 0. , 0. ],
|
|
35
|
+
[ 0.5, 0.5, 0. ],
|
|
36
|
+
[ 0. , 0. , 0. ]])
|
|
37
|
+
"""
|
|
38
|
+
nsym = len(symlist)
|
|
39
|
+
rot = np.zeros((nsym, 3, 3), dtype='int')
|
|
40
|
+
trans = np.zeros((nsym, 3))
|
|
41
|
+
|
|
42
|
+
trans_pattern = r"([-+]?\d*\.\d*|[-+]?\d+)"
|
|
43
|
+
re_trans = re.compile(trans_pattern)
|
|
44
|
+
rot_pattern=r"[+-]?[xyz]"
|
|
45
|
+
re_rot = re.compile(rot_pattern)
|
|
46
|
+
|
|
47
|
+
for i, sym in enumerate(symlist):
|
|
48
|
+
for j, s in enumerate(sym.split(sep)):
|
|
49
|
+
s = s.lower().strip()
|
|
50
|
+
#得到旋转字符
|
|
51
|
+
strs_matches = re_rot.findall(s)
|
|
52
|
+
#得到偏移数字
|
|
53
|
+
numbers_matches = re_trans.findall(s)
|
|
54
|
+
if len(numbers_matches)==2:
|
|
55
|
+
trans[i, j] = float(numbers_matches[0]) / float(numbers_matches[1])
|
|
56
|
+
elif len(numbers_matches)==1:
|
|
57
|
+
trans[i, j] = float(numbers_matches[0])
|
|
58
|
+
elif len(numbers_matches)==0:
|
|
59
|
+
trans[i, j] = 0.0
|
|
60
|
+
else:
|
|
61
|
+
raise Exception("Read symmetry trans string error")
|
|
62
|
+
if len(strs_matches)<1:
|
|
63
|
+
raise Exception(
|
|
64
|
+
'Error parsing %r. Invalid site symmetry: %s' %
|
|
65
|
+
(s, sym))
|
|
66
|
+
for sxyz in strs_matches:
|
|
67
|
+
sign = 1.0
|
|
68
|
+
if len(sxyz)==2:
|
|
69
|
+
if sxyz[0] in '+-':
|
|
70
|
+
if sxyz[0] == '-':
|
|
71
|
+
sign = -1.0
|
|
72
|
+
xyz=sxyz[1]
|
|
73
|
+
elif len(sxyz)==1:
|
|
74
|
+
xyz=sxyz[0]
|
|
75
|
+
sign = 1.0
|
|
76
|
+
else:
|
|
77
|
+
raise Exception(
|
|
78
|
+
'Error parsing %r. Invalid site symmetry: %s' %
|
|
79
|
+
(s, sym))
|
|
80
|
+
if xyz in 'xyz':
|
|
81
|
+
k = ord(xyz) - ord('x')
|
|
82
|
+
rot[i, j, k] = sign
|
|
83
|
+
return rot, trans
|
|
84
|
+
def get_lattice_vectors(a, b, c, alpha, beta, gamma) -> np.ndarray:
|
|
85
|
+
"""Get the cell vectors matrix(fix a-axis) from the cell parameters
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
a : float
|
|
89
|
+
晶格参数:a
|
|
90
|
+
b : float
|
|
91
|
+
晶格参数:b
|
|
92
|
+
c : float
|
|
93
|
+
晶格参数:c
|
|
94
|
+
alpha : float
|
|
95
|
+
晶格参数:alpha
|
|
96
|
+
beta : float
|
|
97
|
+
晶格参数:beta
|
|
98
|
+
gamma : float
|
|
99
|
+
晶格参数:gamma
|
|
100
|
+
|
|
101
|
+
Returns
|
|
102
|
+
-------
|
|
103
|
+
numpy.ndarray
|
|
104
|
+
晶格矢量矩阵
|
|
105
|
+
"""
|
|
106
|
+
angles_r = np.radians([alpha, beta, gamma])
|
|
107
|
+
cos_alpha, cos_beta, cos_gamma = np.cos(angles_r)
|
|
108
|
+
sin_alpha, sin_beta, sin_gamma = np.sin(angles_r)
|
|
109
|
+
|
|
110
|
+
# fix a-axis
|
|
111
|
+
vector_a = a * np.array([1, 0, 0])
|
|
112
|
+
vector_b = b * np.array([cos_gamma, sin_gamma, 0])
|
|
113
|
+
cx = cos_beta
|
|
114
|
+
cy = (cos_alpha - cos_beta * cos_gamma) / sin_gamma
|
|
115
|
+
cz_sqr = 1. - cx * cx - cy * cy
|
|
116
|
+
cz = np.sqrt(cz_sqr)
|
|
117
|
+
vector_c = c * np.array([cx, cy, cz])
|
|
118
|
+
return np.array([vector_a, vector_b, vector_c])
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_lattice_parameters(lattice_vectors: np.ndarray) -> Tuple:
|
|
122
|
+
"""get lattice parameters from the lattice vectors matrix
|
|
123
|
+
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
lattice_vectors : np.ndarray
|
|
127
|
+
晶格矢量
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
元组类型
|
|
132
|
+
返回晶格常数:a,b,c,alpha,beta,gamma
|
|
133
|
+
"""
|
|
134
|
+
abc = np.linalg.norm(lattice_vectors, axis=1)
|
|
135
|
+
arc_alpha = np.arccos(np.dot(lattice_vectors[1], lattice_vectors[2]) / (abc[1] * abc[2]))
|
|
136
|
+
arc_beta = np.arccos(np.dot(lattice_vectors[0], lattice_vectors[2]) / (abc[0] * abc[2]))
|
|
137
|
+
arc_gamma = np.arccos(np.dot(lattice_vectors[1], lattice_vectors[0]) / (abc[1] * abc[0]))
|
|
138
|
+
arc_values = np.array([arc_alpha, arc_beta, arc_gamma])
|
|
139
|
+
alpha, beta, gamma = arc_values * 180 / math.pi
|
|
140
|
+
return tuple([abc[0], abc[1], abc[2], alpha, beta, gamma])
|
|
141
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: mgtoolbox-kernel
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Home-page: https://gitee.com/shuhebing/mgtoolbox_kernel
|
|
5
|
+
Author: Bing He
|
|
6
|
+
Author-email: shhebing@qq.com
|
|
7
|
+
Requires-Python: >=3.7,<=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: pycifrw
|
|
10
|
+
Requires-Dist: numpy
|
|
11
|
+
Requires-Dist: scipy
|
|
12
|
+
Requires-Dist: pandas
|
|
13
|
+
Requires-Dist: spglib
|
|
14
|
+
|
|
15
|
+
# MGToolBox Materials Genome Toolbox
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
mgtoolbox_kernel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
mgtoolbox_kernel/io/__init__.py,sha256=c7NUxkUR7IzAvZKHEqa_81DaH-kZACXY748xWrXd1aA,868
|
|
3
|
+
mgtoolbox_kernel/io/cif.py,sha256=vTqlmr7ONMPrhm3ytooqMNcpVm2_AA6o8bt3IAubZD4,6763
|
|
4
|
+
mgtoolbox_kernel/io/vasp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
mgtoolbox_kernel/io/vasp/poscar.py,sha256=ISmldKyDYVK50IySxvOByEqGHnP-bbjuQkD39JVNjqI,4559
|
|
6
|
+
mgtoolbox_kernel/kernel/__init__.py,sha256=yzBH8rszXZTN8zjbpCG1iraBEsv7uMk3GlUEWoxOytM,32
|
|
7
|
+
mgtoolbox_kernel/kernel/atom.py,sha256=mGV-IC7-WjuEe7ItEh3pHx0wi87uAtWRyOFhgKTGG9s,1430
|
|
8
|
+
mgtoolbox_kernel/kernel/cell.py,sha256=n0NzltcoQiEy3fuFMP0cLc1UwjnslTnuuVgFpa1AviY,15296
|
|
9
|
+
mgtoolbox_kernel/kernel/mgclass.py,sha256=7g_IdostJg7MgQLq-9geIzYI9ccouSDB-vI77xttKXw,179
|
|
10
|
+
mgtoolbox_kernel/kernel/potential.py,sha256=zM50evBCTiYhFEeOzKdPsyvmqpBeClOqra3s0fHnm20,3329
|
|
11
|
+
mgtoolbox_kernel/kernel/site.py,sha256=93_f1-np31o46ouXha-3SpNknymY4ng8QXQoGwmrYDs,5529
|
|
12
|
+
mgtoolbox_kernel/kernel/structure.py,sha256=GtLd38cSo1tWjcVk-bywPn0qC2umCXX2T1981cHJl2Y,6805
|
|
13
|
+
mgtoolbox_kernel/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
mgtoolbox_kernel/util/base.py,sha256=n1YnhXpqhB9eFyTyxMhRff8QU9egtQ3wMxMMyGNqw_0,4431
|
|
15
|
+
mgtoolbox_kernel-0.1.0.dist-info/METADATA,sha256=uVzqlJiFhGAE45fC_mHqFC85lzeceQy6Iw2EpKgzz_E,394
|
|
16
|
+
mgtoolbox_kernel-0.1.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
|
17
|
+
mgtoolbox_kernel-0.1.0.dist-info/top_level.txt,sha256=Od6EGc_Q9VZLH9OaHl7lcjfJBBZQ-rjhZujgsw8-tRs,17
|
|
18
|
+
mgtoolbox_kernel-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mgtoolbox_kernel
|