draw_rhombohedral_cells.py ダウンロード/コピー
draw_rhombohedral_cells.py をダウンロード
draw_rhombohedral_cells.py
draw_rhombohedral_cells.py
1"""
2六方格子(Hexagonal)と菱面体格子(Rhombohedral)の幾何学的関係を可視化するモジュール。
3
4概要:
5 このスクリプトは、六方格子の基本ベクトル a1, a2, a3 を定義し、
6 変換行列 T を用いて菱面体格子の基本ベクトル r1, r2, r3 へ変換します。
7 変換後の格子ベクトルおよび単位格子を 3D 空間上に描画し、両者の関係を視覚化します。
8
9詳細説明:
10 このスクリプトは以下の手順で処理を実行します。
11 1. 六方格子の軸長 aH, cH に基づき、直交座標系での格子ベクトルを生成します。
12 2. 六方→菱面体の変換行列 T を適用し、菱面体格子の基底を計算します。
13 3. 3D 矢印(Arrow3D クラス)を用いて格子ベクトルを描画します。
14 4. 平行六面体(単位格子)を描画し、空間的な重なりを示します。
15
16変換式:
17 菱面体格子ベクトルを Rrhombo、六方格子ベクトルを Ahex とすると、
18 Rrhombo = T @ Ahex で表されます。
19"""
20
21import numpy as np
22import matplotlib.pyplot as plt
23from matplotlib import rcParams
24from matplotlib.patches import FancyArrowPatch
25from mpl_toolkits.mplot3d import Axes3D, proj3d
26
27#===================
28# グローバル設定
29#===================
30# フォント設定(日本語化対策)
31rcParams['font.family'] = 'MS Gothic'
32
33class Arrow3D(FancyArrowPatch):
34 """
35 概要:
36 3D空間に矢印を描画するためのmatplotlib拡張クラスです。
37
38 詳細説明:
39 matplotlib.patches.FancyArrowPatch を継承し、
40 3D座標を受け取って2D投影された矢印として描画します。
41 主に draw メソッドと do_3d_projection メソッドが3D描画のためにオーバーライドされています。
42
43 引数:
44 :param xs: 矢印のX座標のリストまたはタプル (開始点X, 終了点X)。
45 :type xs: list or tuple
46 :param ys: 矢印のY座標のリストまたはタプル (開始点Y, 終了点Y)。
47 :type ys: list or tuple
48 :param zs: 矢印のZ座標のリストまたはタプル (開始点Z, 終了点Z)。
49 :type zs: list or tuple
50 :param args: FancyArrowPatch に渡される追加の位置引数。
51 :param kwargs: FancyArrowPatch に渡される追加のキーワード引数。
52 """
53 def __init__(self, xs, ys, zs, *args, **kwargs):
54 super().__init__((0, 0), (0, 0), *args, **kwargs)
55 self._verts3d = xs, ys, zs
56
57 def draw(self, renderer):
58 xs3d, ys3d, zs3d = self._verts3d
59 proj = self.axes.get_proj()
60 xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, proj)
61 self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
62 super().draw(renderer)
63
64 def do_3d_projection(self, renderer=None):
65 xs3d, ys3d, zs3d = self._verts3d
66 proj = self.axes.get_proj()
67 xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, proj)
68 self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
69 return np.min(zs)
70
71def draw_unit_cell(ax, origin, v1, v2, v3, color='black', lw=0.5):
72 """
73 概要:
74 指定された3つのベクトルに基づいて平行六面体(単位格子)を描画します。
75
76 詳細説明:
77 原点 origin から始まり、3つの基底ベクトル v1, v2, v3 で定義される
78 平行六面体の全ての辺を描画します。これにより単位格子が可視化されます。
79
80 引数:
81 :param ax: 描画対象の3D Axesオブジェクト。
82 :type ax: mpl_toolkits.mplot3d.axes3d.Axes3D
83 :param origin: 格子の原点座標。
84 :type origin: numpy.ndarray
85 :param v1: 単位格子を構成する第一のベクトル。
86 :type v1: numpy.ndarray
87 :param v2: 単位格子を構成する第二のベクトル。
88 :type v2: numpy.ndarray
89 :param v3: 単位格子を構成する第三のベクトル。
90 :type v3: numpy.ndarray
91 :param color: 描画する線の色。デフォルトは 'black'。
92 :type color: str
93 :param lw: 描画する線の太さ。デフォルトは 0.5。
94 :type lw: float
95 """
96 O = origin
97 A = O + v1
98 B = O + v2
99 C = O + v3
100 D = O + v1 + v2
101 E = O + v2 + v3
102 F = O + v3 + v1
103 G = O + v1 + v2 + v3
104
105 edges = [
106 (O, A), (O, B), (O, C),
107 (A, D), (A, F),
108 (B, D), (B, E),
109 (C, E), (C, F),
110 (D, G), (E, G), (F, G)
111 ]
112
113 for start, end in edges:
114 ax.plot([start[0], end[0]],
115 [start[1], end[1]],
116 [start[2], end[2]],
117 color=color, lw=lw)
118
119def draw_vector(ax, vec, color, label, fontsize):
120 """
121 概要:
122 3D空間にベクトル(矢印)とそのラベルを描画します。
123
124 詳細説明:
125 指定されたベクトルを原点 (0,0,0) から開始する矢印として Axes オブジェクト ax に追加します。
126 矢印の終点付近に、指定されたラベルを配置します。
127
128 引数:
129 :param ax: 描画対象の3D Axesオブジェクト。
130 :type ax: mpl_toolkits.mplot3d.axes3d.Axes3D
131 :param vec: 描画するベクトルの終点座標。原点 (0,0,0) から開始します。
132 :type vec: numpy.ndarray
133 :param color: 矢印とラベルの色。
134 :type color: str
135 :param label: ベクトルに表示するテキストラベル。
136 :type label: str
137 :param fontsize: ラベルのフォントサイズ。
138 :type fontsize: int or float
139 """
140 arrow = Arrow3D([0, vec[0]], [0, vec[1]], [0, vec[2]],
141 mutation_scale=20, lw=2, arrowstyle="-|>", color=color)
142 ax.add_artist(arrow)
143 ax.text(vec[0] * 1.05, vec[1] * 1.05, vec[2] * 1.05, label, fontsize=fontsize, color=color)
144
145def main():
146 """
147 概要:
148 格子変換の計算と描画を実行するメインルーチンです。
149
150 詳細説明:
151 六方格子の軸長を定義し、六方格子ベクトルと格子点を計算します。
152 その後、六方→菱面体の変換行列を適用して菱面体格子ベクトルと格子点を導出します。
153 最後に、matplotlib を使用してこれらの格子ベクトルと単位格子を3D空間に描画し、
154 六方格子の外郭も表示して、両格子の関係性を視覚的に示します。
155 """
156 axis_label_font_size = 24
157
158 # 六方格子の軸長
159 a_H = 1.0
160 c_H = 1.6
161
162 # 六方格子ベクトル
163 a1 = np.array([a_H, 0, 0])
164 a2 = np.array([-a_H/2, a_H*np.sqrt(3)/2, 0])
165 a3 = np.array([0, 0, c_H])
166
167 # 六方格子点
168 hex_points = []
169 for i in range(2):
170 for j in range(2):
171 for k in range(2):
172 pt = i*a1 + j*a2 + k*a3
173 hex_points.append(pt)
174 hex_points = np.array(hex_points)
175
176 # 六方格子ベクトルを行ベクトルとして並べる
177 A_hex = np.array([a1, a2, a3])
178
179 # 六方→菱面体変換行列 T
180 T = np.array([
181 [ 2/3, 1/3, 1/3],
182 [-1/3, 1/3, 1/3],
183 [-1/3, -2/3, 1/3]
184 ])
185
186 # 菱面体格子ベクトルを計算(T @ A_hex)
187 R_rhombo = T @ A_hex
188 r1, r2, r3 = R_rhombo
189
190 # 菱面体格子点
191 rhombo_points = []
192 for i in range(2):
193 for j in range(2):
194 for k in range(2):
195 pt = i*r1 + j*r2 + k*r3
196 rhombo_points.append(pt)
197 rhombo_points = np.array(rhombo_points)
198
199 # --- 描画開始 ---
200 fig = plt.figure(figsize=(10, 8))
201 ax = fig.add_subplot(111, projection='3d')
202
203 # 格子ベクトル描画
204 draw_vector(ax, a1, 'blue', 'a(H)', axis_label_font_size)
205 draw_vector(ax, a2, 'blue', 'b(H)', axis_label_font_size)
206 draw_vector(ax, a3, 'blue', 'c(H)', axis_label_font_size)
207 draw_vector(ax, r1, 'red', 'a(R)', axis_label_font_size)
208 draw_vector(ax, r2, 'red', 'b(R)', axis_label_font_size)
209 draw_vector(ax, r3, 'red', 'c(R)', axis_label_font_size)
210
211 # 単位格子描画
212 draw_unit_cell(ax, origin=np.array([0,0,0]), v1=a1, v2=a2, v3=a3, color='blue', lw=0.5)
213 draw_unit_cell(ax, origin=np.array([0,0,0]), v1=r1, v2=r2, v3=r3, color='red', lw=0.5)
214
215 # 格子点のプロット
216 ax.scatter(hex_points[:,0], hex_points[:,1], hex_points[:,2], color='blue', alpha=0.6)
217 ax.scatter(rhombo_points[:,0], rhombo_points[:,1], rhombo_points[:,2], color='red', alpha=0.6)
218
219 # 六角柱描画(外郭)
220 theta = np.linspace(0, 2*np.pi, 7)
221 r = a_H
222 z_vals = [0, c_H]
223 for z in z_vals:
224 x = r * np.cos(theta)
225 y = r * np.sin(theta)
226 ax.plot(x, y, z, color='gray', alpha=0.5)
227 for i in range(6):
228 x = [r*np.cos(theta[i]), r*np.cos(theta[i])]
229 y = [r*np.sin(theta[i]), r*np.sin(theta[i])]
230 z = [0, c_H]
231 ax.plot(x, y, z, color='gray', alpha=0.5)
232
233 # グラフ設定
234 ax.set_axis_off()
235 ax.grid(False)
236 ax.set_box_aspect([1,1,1])
237 ax.view_init(elev=20, azim=30)
238 plt.tight_layout()
239 plt.show()
240
241if __name__ == "__main__":
242 main()