tkcrystalbase.py ダウンロード/コピー
tkcrystalbase.py
tkcrystalbase.py
1"""
2tkcrystalbase.py
3
4概要: 結晶構造計算と描画に関連するユーティリティ関数を提供するモジュール。
5詳細説明:
6 このモジュールは、結晶の格子定数から実空間および逆空間の格子ベクトル、
7 メトリックテンソル、単位格子の体積などを計算する機能を提供します。
8 また、原子の分数座標とデカルト座標間の変換、原子間距離や角度の計算、
9 そしてmatplotlibを使用した3D描画ヘルパー関数を含んでいます。
10 物理定数や一般的な格子パラメータ、サイト情報もここで定義されています。
11
12関連リンク:
13 :doc:`tkcrystalbase_usage`
14"""
15
16from numpy import sin, cos, tan, arcsin, arccos, arctan, exp, log, sqrt
17import numpy as np
18from numpy import linalg as la
19from pprint import pprint
20
21pi = 3.14159265358979323846
22pi2 = pi + pi
23torad = 0.01745329251944 # rad/deg";
24todeg = 57.29577951472 # deg/rad";
25basee = 2.71828183
26
27h = 6.6260755e-34 # Js";
28h_bar = 1.05459e-34 # "Js";
29hbar = h_bar
30c = 2.99792458e8 # m/s";
31e = 1.60218e-19 # C";
32me = 9.1093897e-31 # kg";
33mp = 1.6726231e-27 # kg";
34mn = 1.67495e-27 # kg";
35u0 = 4.0 * 3.14*1e-7; # . "Ns<sup>2</sup>C<sup>-2</sup>";
36e0 = 8.854418782e-12; # C<sup>2</sup>N<sup>-1</sup>m<sup>-2</sup>";
37e2_4pie0 = 2.30711e-28 # Nm<sup>2</sup>";
38a0 = 5.29177e-11 # m";
39kB = 1.380658e-23 # JK<sup>-1</sup>";
40NA = 6.0221367e23 # mol<sup>-1</sup>";
41R = 8.31451 # J/K/mol";
42F = 96485.3 # C/mol";
43g = 9.81 # m/s2";
44
45
46# Lattice parameters (angstrom and degree)
47#lattice_parameters = [ 5.62, 5.62, 5.62, 60.0, 60.0, 60.0]
48lattice_parameters = [ 5.62, 5.62, 5.62, 90.0, 90.0, 90.0]
49
50# Site information (atom name, site label, atomic number, atomic mass, charge, radius, color, position)
51sites = [
52 ['Na', 'Na1', 11, 22.98997, +1.0, 0.7, 'red', np.array([0.0, 0.0, 0.0])]
53 ,['Na', 'Na2', 11, 22.98997, +1.0, 0.7, 'red', np.array([0.0, 0.5, 0.5])]
54 ,['Na', 'Na3', 11, 22.98997, +1.0, 0.7, 'red', np.array([0.5, 0.0, 0.5])]
55 ,['Na', 'Na4', 11, 22.98997, +1.0, 0.7, 'red', np.array([0.5, 0.5, 0.0])]
56 ,['Cl', 'Cl1', 17, 35.4527, +1.0, 1.4, 'blue', np.array([0.5, 0.0, 0.0])]
57 ,['Cl', 'Cl2', 17, 35.4527, +1.0, 1.4, 'blue', np.array([0.5, 0.5, 0.5])]
58 ,['Cl', 'Cl3', 17, 35.4527, +1.0, 1.4, 'blue', np.array([0.0, 0.0, 0.5])]
59 ,['Cl', 'Cl4', 17, 35.4527, +1.0, 1.4, 'blue', np.array([0.0, 0.5, 0.0])]
60 ]
61
62
63def reduce01(x):
64 """
65 概要: 数値を0以上1未満の範囲に変換する。
66 詳細説明:
67 入力された数値の小数部分を返します。
68 例えば、3.75は0.75に、-2.3は0.7に変換されます。
69 :param x: float: 変換する数値。
70 :returns: float: 0以上1未満の範囲に変換された値。
71 """
72 return x - int(x)
73
74 return x
75
76def round01(x):
77 """
78 概要: 数値を特定の閾値に基づいて0または1に丸めるか、0以上1未満の範囲に変換する。
79 詳細説明:
80 `x` が1.0に近い(絶対差が0.0002未満)場合は1.0を返します。
81 `x` が0.0に近い(絶対差が0.0002未満)場合は0.0を返します。
82 それ以外の場合、`x > 1.0` なら `x - int(x)` を返します。
83 `x < 1.0` なら `x - int(x) + 1.0` を返します。
84 この関数は、負の数や1を超える数値を0以上1未満の範囲に正規化するために使用されることがあります。
85 :param x: float: 丸める、または変換する数値。
86 :returns: float: 丸められた、または0以上1未満の範囲に変換された値。
87 """
88 if abs(x - 1.0) < 0.0002:
89 return 1.0
90 if abs(x) < 0.0002:
91 return 0.0
92 if x > 1.0:
93 return x - int(x)
94 if x < 1.0:
95 return x - int(x) + 1.0
96 return x
97
98def round_parameter(x, tol):
99 """
100 概要: 数値を指定された許容範囲 (tolerance) の整数倍に丸める。
101 詳細説明:
102 入力値 `x` を `tol` の整数倍に丸めます。
103 丸め処理は、`(x + 0.1 * tol) / tol` を整数に変換し、`tol` を掛けることで行われます。
104 これにより、例えば `tol=0.5` で `x=1.2` なら `1.0` に、`x=1.3` なら `1.5` に丸められます。
105 :param x: float: 丸める数値。
106 :param tol: float: 丸めの基準となる許容範囲(単位)。
107 :returns: float: `tol` の整数倍に丸められた値。
108 """
109 val = tol * int( (x+0.1*tol) / tol )
110 return val
111
112
113def cal_lattice_vectors(latt):
114 """
115 概要: 単位格子の格子定数から実空間の格子ベクトルを計算する。
116 詳細説明:
117 格子定数 (a, b, c, α, β, γ) を受け取り、
118 直交座標系における3つの格子ベクトル a_vec, b_vec, c_vec を含む3x3行列を計算します。
119 格子ベクトルは、x軸に沿って a_vec が配置されるように構成されます。
120 角度は度数で指定されますが、内部ではラジアンに変換して計算されます。
121 :param latt: list of float: 格子定数のリスト `[a, b, c, alpha, beta, gamma]`。
122 長さはオングストローム、角度は度で与えられます。
123 :returns: numpy.ndarray: 3x3 の格子ベクトル行列。
124 `[[ax_x, ax_y, ax_z], [ay_x, ay_y, ay_z], [az_x, az_y, az_z]]` の形式。
125 """
126 cosa = cos(torad * latt[3])
127 cosb = cos(torad * latt[4])
128 cosg = cos(torad * latt[5])
129 sing = sin(torad * latt[5])
130
131 aij = np.empty([3, 3], dtype = float)
132 aij[0][0] = latt[0]
133 aij[0][1] = 0.0;
134 aij[0][2] = 0.0;
135 aij[1][0] = latt[1] * cosg
136 aij[1][1] = latt[1] * sing
137 aij[1][2] = 0.0;
138 aij[2][0] = latt[2] * cosb
139 aij[2][1] = latt[2] * (cosa - cosb * cosg) / sing
140 if abs(aij[2][1]) < 1.0e-8:
141 aij[2][1] = 0.0
142 else:
143 aij[2][1] = aij[2][1] / sing
144 aij[2][2] = sqrt(latt[2] * latt[2] - aij[2][0] * aij[2][0] - aij[2][1] * aij[2][1])
145
146 return aij
147
148def cal_metrics(latt):
149 """
150 概要: 格子定数から格子ベクトルとメトリックテンソルを計算する。
151 詳細説明:
152 単位格子の格子定数から実空間の格子ベクトル `aij` を計算し、
153 それらの内積からメトリックテンソル `gij` を構築します。
154 結果は辞書形式で返されます。
155 :param latt: list of float: 格子定数のリスト `[a, b, c, alpha, beta, gamma]`。
156 長さはオングストローム、角度は度で与えられます。
157 :returns: dict: 計算された格子ベクトル行列 (`'aij'`) とメトリックテンソル (`'gij'`)
158 をキーに持つ辞書。
159 `{'aij': numpy.ndarray, 'gij': numpy.ndarray}` の形式。
160 """
161 inf = {}
162
163 cosa = cos(torad * latt[3])
164 cosb = cos(torad * latt[4])
165 cosg = cos(torad * latt[5])
166
167 aij = cal_lattice_vectors(latt)
168 inf['aij'] = aij
169
170 gij = np.empty([3, 3], dtype = float)
171 for i in range(3):
172 for j in range(i, 3):
173 gij[i][j] = np.dot(aij[i], aij[j])
174 gij[j][i] = gij[i][j]
175 inf['gij'] = gij
176
177 return inf
178
179def cal_volume(aij):
180 """
181 概要: 格子ベクトルから単位格子の体積を計算する。
182 詳細説明:
183 3つの格子ベクトル (a_vec, b_vec, c_vec) のスカラー三重積 (a_vec・(b_vec × c_vec)) を用いて、
184 単位格子の体積を計算します。
185 :param aij: numpy.ndarray: 3x3 の格子ベクトル行列。
186 `[[ax_x, ax_y, ax_z], [ay_x, ay_y, ay_z], [az_x, az_y, az_z]]` の形式。
187 :returns: float: 単位格子の体積。
188 """
189 axb = np.cross(aij[0], aij[1]) # Outner product
190 vol = np.dot(axb, aij[2]) # Inner product
191 return vol
192
193def cal_reciprocal_lattice_vectors(aij):
194 """
195 概要: 実空間格子ベクトルから逆空間格子ベクトルを計算する。
196 詳細説明:
197 実空間の格子ベクトル `aij` (a_vec, b_vec, c_vec) を用いて、
198 逆空間の格子ベクトル (a*_vec, b*_vec, c*_vec) を計算します。
199 逆空間ベクトルは、単位格子の体積 V と実空間ベクトルの外積によって定義されます。
200 :param aij: numpy.ndarray: 3x3 の実空間格子ベクトル行列。
201 `[[ax_x, ax_y, ax_z], [ay_x, ay_y, ay_z], [az_x, az_y, az_z]]` の形式。
202 :returns: list of numpy.ndarray: 逆空間の3つの格子ベクトル `[Ra_vec, Rb_vec, Rc_vec]` のリスト。
203 """
204 V = cal_volume(aij)
205 Ra = np.cross(aij[1], aij[2]) / V
206 Rb = np.cross(aij[2], aij[0]) / V
207 Rc = np.cross(aij[0], aij[1]) / V
208
209 return [Ra, Rb, Rc]
210
211def cal_reciprocal_lattice_parameters(Raij):
212 """
213 概要: 逆空間格子ベクトルから逆空間の格子定数を計算する。
214 詳細説明:
215 逆空間の格子ベクトル `Raij` (a*_vec, b*_vec, c*_vec) を用いて、
216 逆空間の格子定数 (a*, b*, c*, α*, β*, γ*) を計算します。
217 長さはベクトルのノルムから、角度はベクトルの内積から導出されます。
218 :param Raij: list of numpy.ndarray: 逆空間の3つの格子ベクトル `[Ra_vec, Rb_vec, Rc_vec]` のリスト。
219 :returns: list of float: 逆空間の格子定数 `[Ra, Rb, Rc, Ralpha, Rbeta, Rgamma]` のリスト。
220 """
221 Ra = la.norm(Raij[0])
222 Rb = la.norm(Raij[1])
223 Rc = la.norm(Raij[2])
224 Ralpha = todeg * arccos(np.dot(Raij[1], Raij[2]) / Rb / Rc)
225 Rbeta = todeg * arccos(np.dot(Raij[2], Raij[0]) / Rc / Ra)
226 Rgamma = todeg * arccos(np.dot(Raij[0], Raij[1]) / Ra / Rb)
227
228 return [Ra, Rb, Rc, Ralpha, Rbeta, Rgamma]
229
230def fractional_to_cartesian(pos, aij):
231 """
232 概要: 分数座標からデカルト座標に変換する。
233 詳細説明:
234 単位格子内の原子の分数座標 (x_frac, y_frac, z_frac) と格子ベクトル `aij` を用いて、
235 原子のデカルト座標 (x_cart, y_cart, z_cart) を計算します。
236 :param pos: numpy.ndarray or list of float: 変換する分数座標 `[x_frac, y_frac, z_frac]`。
237 :param aij: numpy.ndarray: 3x3 の格子ベクトル行列。
238 `[[ax_x, ax_y, ax_z], [ay_x, ay_y, ay_z], [az_x, az_y, az_z]]` の形式。
239 :returns: tuple of float: 計算されたデカルト座標 `(x_cart, y_cart, z_cart)`。
240 """
241 x = pos[0] * aij[0][0] + pos[1] * aij[1][0] + pos[2] * aij[2][0]
242 y = pos[0] * aij[0][1] + pos[1] * aij[1][1] + pos[2] * aij[2][1]
243 z = pos[0] * aij[0][2] + pos[1] * aij[1][2] + pos[2] * aij[2][2]
244
245 return x, y, z
246
247def distance2(pos0, pos1, gij):
248 """
249 概要: 2つの分数座標間の距離の2乗を計算する。
250 詳細説明:
251 2つの原子の分数座標 `pos0` と `pos1` の間の距離の2乗を、
252 メトリックテンソル `gij` を使用して計算します。
253 この関数は周期境界条件を考慮しません。
254 :param pos0: numpy.ndarray or list of float: 1点目の分数座標 `[x0, y0, z0]`。
255 :param pos1: numpy.ndarray or list of float: 2点目の分数座標 `[x1, y1, z1]`。
256 :param gij: numpy.ndarray: 3x3 のメトリックテンソル。
257 :returns: float: 2点間の距離の2乗。
258 """
259 dx = pos1 - pos0
260# dx = [pos1[0] - pos0[0], pos1[1] - pos0[1], pos1[2] - pos0[2]]
261 r2 = gij[0][0] * dx[0]*dx[0] + gij[1][1] * dx[1]*dx[1] + gij[2][2] * dx[2]*dx[2] \
262 + 2.0 * (gij[0][1] * dx[0]*dx[1] + gij[0][2] * dx[0]*dx[2] + gij[1][2] * dx[1]*dx[2])
263
264 return r2
265
266def distance(pos0, pos1, gij):
267 """
268 概要: 2つの分数座標間の距離を計算する。
269 詳細説明:
270 2つの原子の分数座標 `pos0` と `pos1` の間の距離を、
271 メトリックテンソル `gij` を使用して計算します。
272 この関数は周期境界条件を考慮しません。
273 :param pos0: numpy.ndarray or list of float: 1点目の分数座標 `[x0, y0, z0]`。
274 :param pos1: numpy.ndarray or list of float: 2点目の分数座標 `[x1, y1, z1]`。
275 :param gij: numpy.ndarray: 3x3 のメトリックテンソル。
276 :returns: float: 2点間の距離。
277 """
278 dx = pos1 - pos0
279# dx = [pos1[0] - pos0[0], pos1[1] - pos0[1], pos1[2] - pos0[2]]
280 r2 = gij[0][0] * dx[0]*dx[0] + gij[1][1] * dx[1]*dx[1] + gij[2][2] * dx[2]*dx[2] \
281 + 2.0 * (gij[0][1] * dx[0]*dx[1] + gij[0][2] * dx[0]*dx[2] + gij[1][2] * dx[1]*dx[2])
282 r = sqrt(r2)
283
284 return r
285
286def angle(pos0, pos1, pos2, gij):
287 """
288 概要: 3つの分数座標で定義される角度を計算する。
289 詳細説明:
290 `pos0` を頂点とし、`pos0-pos1` と `pos0-pos2` の2つのベクトルがなす角度を計算します。
291 角度の計算にはメトリックテンソル `gij` が使用されます。
292 結果は度数で返され、180度を超える場合は `360.0 - angle` として調整されます。
293 :param pos0: numpy.ndarray or list of float: 角度の頂点となる分数座標 `[x0, y0, z0]`。
294 :param pos1: numpy.ndarray or list of float: 1つ目のベクトルを定義する分数座標 `[x1, y1, z1]`。
295 :param pos2: numpy.ndarray or list of float: 2つ目のベクトルを定義する分数座標 `[x2, y2, z2]`。
296 :param gij: numpy.ndarray: 3x3 のメトリックテンソル。
297 :returns: float: 3点間で形成される角度(度)。
298 いずれかの距離が0の場合は0.0を返します。
299 """
300 dis01 = distance(pos0, pos1, gij)
301 if dis01 == 0.0:
302 return 0.0
303 dis02 = distance(pos0, pos2, gij)
304 if dis02 == 0.0:
305 return 0.0
306
307 dx01 = pos1 - pos0
308 dx02 = pos2 - pos0
309# dx01 = [pos1[0] - pos0[0], pos1[1] - pos0[1], pos1[2] - pos0[2]]
310# dx02 = [pos2[0] - pos0[0], pos2[1] - pos0[1], pos2[2] - pos0[2]]
311 ip = gij[0][0] * dx01[0]*dx02[0] + gij[1][1] * dx01[1]*dx02[1] + gij[2][2] * dx01[2]*dx02[2] \
312 + 2.0 * (gij[0][1] * dx01[0]*dx02[1] + gij[0][2] * dx01[0]*dx02[2] + gij[1][2] * dx01[1]*dx02[2])
313
314 cosa = ip / dis01 / dis02
315 angle = todeg * arccos(cosa)
316 if angle > 180.0:
317 angle = 360.0 - angle
318
319 return angle;
320
321def configure_axis_structure(ax, xrange, yrange, zrange, fontsize = 12, legend_fontsize = 12):
322 """
323 概要: Matplotlibの3D軸オブジェクトの表示設定を行う。
324 詳細説明:
325 MatplotlibのAxes3Dオブジェクト (`ax`) に対して、軸ラベルのフォントサイズ、
326 軸の線、目盛り、グリッド、ペインの表示設定をカスタマイズします。
327 デフォルトでは、軸の線、目盛り、ラベルは非表示に設定され、
328 箱型のアスペクト比で視覚的に整えられます。
329 :param ax: matplotlib.axes.Axes: 設定を行うMatplotlibの3D軸オブジェクト。
330 :param xrange: tuple or list of float: x軸の表示範囲 `(xmin, xmax)`。
331 :param yrange: tuple or list of float: y軸の表示範囲 `(ymin, ymax)`。
332 :param zrange: tuple or list of float: z軸の表示範囲 `(zmin, zmax)`。
333 :param fontsize: int, optional: 軸ラベルおよび目盛りのフォントサイズ。
334 0以下の場合は軸ラベルと目盛りを非表示にします。デフォルトは12。
335 :param legend_fontsize: int, optional: 凡例のフォントサイズ(この関数では直接使用されません)。デフォルトは12。
336 :returns: None
337 """
338 ax.tick_params(axis = 'both', which = 'major', labelsize = fontsize)
339 if fontsize > 0:
340 ax.set_xlabel(f'$x$', fontsize = fontsize, labelpad = -5)
341 ax.set_ylabel(f'$y$', fontsize = fontsize, labelpad = -5)
342 ax.set_zlabel(f'$z$', fontsize = fontsize, labelpad = 0)
343
344# x軸、y軸、z軸の線を非表示にする
345 ax.xaxis.line.set_visible(False)
346 ax.yaxis.line.set_visible(False)
347 ax.zaxis.line.set_visible(False)
348
349 ax.grid(False)
350 ax.xaxis.pane.fill = False
351 ax.yaxis.pane.fill = False
352 ax.zaxis.pane.fill = False
353 ax.xaxis.pane.set_edgecolor('w')
354 ax.yaxis.pane.set_edgecolor('w')
355 ax.zaxis.pane.set_edgecolor('w')
356 ax.xaxis.pane.set_alpha(0)
357 ax.yaxis.pane.set_alpha(0)
358 ax.zaxis.pane.set_alpha(0)
359# ax.w_xaxis.line.set_color('none')
360# ax.w_yaxis.line.set_color('none')
361# ax.w_zaxis.line.set_color('none')
362 ax.set_xticks([])
363 ax.set_yticks([])
364 ax.set_zticks([])
365 ax.set_xticklabels([])
366 ax.set_yticklabels([])
367 ax.set_zticklabels([])
368
369 ax.set_xlim(xrange)
370 ax.set_ylim(yrange)
371 ax.set_zlim(zrange)
372 ax.set_aspect('equal','box')
373# ax.set_box_aspect([xrange[1] - xrange[0], yrange[1] - yrange[0], zrange[1] - zrange[0]])
374
375def draw_box(ax, aij, nrange, color = 'black'):
376 """
377 概要: 3D軸上に単位格子のボックスを描画する。
378 詳細説明:
379 格子ベクトル `aij` で定義される単位格子の12本の辺を、Matplotlibの3D軸 `ax` に描画します。
380 この関数は、単一の単位格子を描画するために設計されており、`nrange` は現在の実装では使用されません。
381 :param ax: matplotlib.axes.Axes: 描画対象のMatplotlib 3D軸オブジェクト。
382 :param aij: numpy.ndarray: 3x3 の格子ベクトル行列。
383 `[[ax_x, ax_y, ax_z], [ay_x, ay_y, ay_z], [az_x, az_y, az_z]]` の形式。
384 :param nrange: list of list of int: 描画するセルの範囲 `[[xmin, xmax], [ymin, ymax], [zmin, zmax]]`。
385 この関数では使用されません。
386 :param color: str, optional: ボックスの線の色。デフォルトは 'black'。
387 :returns: None
388 """
389# (0,0,0) -> ax
390 ax.plot([0.0, aij[0][0]],
391 [0.0, aij[0][1]],
392 [0.0, aij[0][2]], color = color)
393# (0,0,0) -> ay
394 ax.plot([0.0, aij[1][0]],
395 [0.0, aij[1][1]],
396 [0.0, aij[1][2]], color = color)
397# (0,0,0) -> az
398 ax.plot([0.0, aij[2][0]],
399 [0.0, aij[2][1]],
400 [0.0, aij[2][2]], color = color)
401
402# ax -> ax + ay
403 ax.plot([aij[0][0], aij[0][0] + aij[1][0]],
404 [aij[0][1], aij[0][1] + aij[1][1]],
405 [aij[0][2], aij[0][2] + aij[1][2]], color = color)
406# ax -> ax + az
407 ax.plot([aij[0][0], aij[0][0] + aij[2][0]],
408 [aij[0][1], aij[0][1] + aij[2][1]],
409 [aij[0][2], aij[0][2] + aij[2][2]], color = color)
410
411# ay -> ay + ax
412 ax.plot([aij[1][0], aij[1][0] + aij[0][0]],
413 [aij[1][1], aij[1][1] + aij[0][1]],
414 [aij[1][2], aij[1][2] + aij[0][2]], color = color)
415# ay -> ay + az
416 ax.plot([aij[1][0], aij[1][0] + aij[2][0]],
417 [aij[1][1], aij[1][1] + aij[2][1]],
418 [aij[1][2], aij[1][2] + aij[2][2]], color = color)
419
420# az -> az + ax
421 ax.plot([aij[2][0], aij[2][0] + aij[0][0]],
422 [aij[2][1], aij[2][1] + aij[0][1]],
423 [aij[2][2], aij[2][2] + aij[0][2]], color = color)
424# az -> ax + ay
425 ax.plot([aij[2][0], aij[2][0] + aij[1][0]],
426 [aij[2][1], aij[2][1] + aij[1][1]],
427 [aij[2][2], aij[2][2] + aij[1][2]], color = color)
428
429# ax + ay -> ax + ay + az
430 ax.plot([aij[0][0] + aij[1][0], aij[0][0] + aij[1][0] + aij[2][0]],
431 [aij[0][1] + aij[1][1], aij[0][1] + aij[1][1] + aij[2][1]],
432 [aij[0][2] + aij[1][2], aij[0][2] + aij[1][2] + aij[2][2]], color = color)
433
434# ax + az -> ax + ay + az
435 ax.plot([aij[0][0] + aij[2][0], aij[0][0] + aij[1][0] + aij[2][0]],
436 [aij[0][1] + aij[2][1], aij[0][1] + aij[1][1] + aij[2][1]],
437 [aij[0][2] + aij[2][2], aij[0][2] + aij[1][2] + aij[2][2]], color = color)
438
439# ay + az -> ax + ay + az
440 ax.plot([aij[1][0] + aij[2][0], aij[0][0] + aij[1][0] + aij[2][0]],
441 [aij[1][1] + aij[2][1], aij[0][1] + aij[1][1] + aij[2][1]],
442 [aij[1][2] + aij[2][2], aij[0][2] + aij[1][2] + aij[2][2]], color = color)
443
444def draw_unitcell(ax, sites, aij, nrange, color = 'black', facecolor = 'black', edgecolor = 'white', alpha = 0.7, kr = 1.0):
445 """
446 概要: 3D軸上に単位格子とその内部のサイト原子を描画する。
447 詳細説明:
448 まず `draw_box` 関数を呼び出して単位格子の境界線を描画します。
449 次に、`sites` リストに含まれる各原子について、その分数座標をデカルト座標に変換し、
450 指定された `nrange` の範囲内の周期的な位置に原子を散布図として描画します。
451 原子の描画スタイル(色、透明度、サイズ)は引数でカスタマイズ可能です。
452 :param ax: matplotlib.axes.Axes: 描画対象のMatplotlib 3D軸オブジェクト。
453 :param sites: list of list: サイト情報(原子名、ラベル、原子番号、原子質量、電荷、半径、色、位置)のリスト。
454 各要素は `[name, label, z, M, q, r, color, pos]` の形式。
455 `None` の場合、原子は描画されません。
456 :param aij: numpy.ndarray: 3x3 の格子ベクトル行列。
457 `[[ax_x, ax_y, ax_z], [ay_x, ay_y, ay_z], [az_x, az_y, az_z]]` の形式。
458 :param nrange: list of list of int: 描画するセルの範囲 `[[xmin, xmax], [ymin, ymax], [zmin, zmax]]`。
459 原子の繰り返し構造を描画するために使用されます。
460 :param color: str, optional: 単位格子ボックスの線の色。デフォルトは 'black'。
461 :param facecolor: str, optional: サイト原子の面の描画色。デフォルトは 'black'。
462 :param edgecolor: str, optional: サイト原子のエッジの描画色。デフォルトは 'white'。
463 :param alpha: float, optional: サイト原子の透明度(0.0から1.0)。デフォルトは 0.7。
464 :param kr: float, optional: サイト原子の描画サイズに対するスケール因子。デフォルトは 1.0。
465 :returns: None
466 """
467 draw_box(ax, aij, nrange, color)
468
469 if sites is None: return
470
471 for isite, site in enumerate(sites):
472 name, label, z, M, q, r, color, pos = site
473 pos01 = [reduce01(pos[0]), reduce01(pos[1]), reduce01(pos[2])]
474 for iz in range(int(nrange[2][0]) - 1, int(nrange[2][1]) + 1):
475 for iy in range(int(nrange[1][0]) - 1, int(nrange[1][1]) + 1):
476 for ix in range(int(nrange[0][0]) - 1, int(nrange[0][1]) + 1):
477 posn = [pos01[0] + ix, pos01[1] + iy, pos01[2] + iz]
478 if posn[0] < nrange[0][0] or nrange[0][1] < posn[0] \
479 or posn[1] < nrange[1][0] or nrange[1][1] < posn[1] \
480 or posn[2] < nrange[2][0] or nrange[2][1] < posn[2]:
481 continue
482
483 x, y, z = fractional_to_cartesian(posn, aij)
484 ax.scatter([x], [y], [z], marker = 'o', c = facecolor, edgecolors = edgecolor, alpha = alpha, s = kr *r)
485
486
487def main():
488 """
489 概要: モジュールの主要な計算と結果の表示を実行する。
490 詳細説明:
491 定義された `lattice_parameters` を使用して、実空間および逆空間の
492 格子ベクトル、メトリックテンソル、単位格子の体積を計算します。
493 さらに、サンプルとして原子間距離と角度の計算も行い、
494 その結果を標準出力に表示します。
495 最後にプログラムを終了します。
496 :returns: None
497 """
498 print("")
499 print("Lattice parameters:", lattice_parameters)
500 aij = cal_lattice_vectors(lattice_parameters)
501 print("Lattice vectors:")
502 print(" ax: ({:10.4g}, {:10.4g}, {:10.4g}) A".format(aij[0][0], aij[0][1], aij[0][2]))
503 print(" ay: ({:10.4g}, {:10.4g}, {:10.4g}) A".format(aij[1][0], aij[1][1], aij[1][2]))
504 print(" az: ({:10.4g}, {:10.4g}, {:10.4g}) A".format(aij[2][0], aij[2][1], aij[2][2]))
505 inf = cal_metrics(lattice_parameters)
506 gij = inf['gij']
507 print("Metric tensor:")
508 print(" gij: ({:10.4g}, {:10.4g}, {:10.4g}) A".format(*gij[0]))
509 print(" ({:10.4g}, {:10.4g}, {:10.4g}) A".format(*gij[1]))
510 print(" ({:10.4g}, {:10.4g}, {:10.4g}) A".format(*gij[2]))
511 print("")
512 volume = cal_volume(aij)
513 print("Volume: {:12.4g} A^3".format(volume))
514
515 print("")
516 print("Unit cell volume: {:12.4g} A^3".format(volume))
517 Raij = cal_reciprocal_lattice_vectors(aij)
518 Rlatt = cal_reciprocal_lattice_parameters(Raij)
519 Rinf = cal_metrics(Rlatt)
520 Rgij = Rinf['gij']
521 print("Reciprocal lattice parameters:", Rlatt)
522 print("Reciprocal lattice vectors:")
523 print(" Rax: ({:10.4g}, {:10.4g}, {:10.4g}) A^-1".format(*Raij[0]))
524 print(" Ray: ({:10.4g}, {:10.4g}, {:10.4g}) A^-1".format(*Raij[1]))
525 print(" Raz: ({:10.4g}, {:10.4g}, {:10.4g}) A^-1".format(*Raij[2]))
526 print("Reciprocal lattice metric tensor:")
527 print(" Rgij: ({:10.4g}, {:10.4g}, {:10.4g}) A^-1".format(*Rgij[0]))
528 print(" ({:10.4g}, {:10.4g}, {:10.4g}) A^-1".format(*Rgij[1]))
529 print(" ({:10.4g}, {:10.4g}, {:10.4g}) A^-1".format(*Rgij[2]))
530 Rvolume = cal_volume(Raij)
531 print("Reciprocal unit cell volume: {:12.4g} A^-3".format(Rvolume))
532
533 print("")
534 print("dis=", distance(np.array([0,0,0]), np.array([1,1,1]), gij))
535 print("angle=", angle (np.array([0,0,0]), np.array([1,1,1]), np.array([1,0,0]), gij))
536 print("angle=", angle (np.array([0,0,0]), np.array([1,0,0]), np.array([0,1,0]), gij))
537
538 print("")
539 exit()
540
541
542if __name__ == '__main__':
543 main()