@nahisaho/satori 0.1.0
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.
- package/LICENCE +0 -0
- package/README.md +191 -0
- package/bin/satori.js +95 -0
- package/package.json +29 -0
- package/src/.github/skills/scientific-academic-writing/SKILL.md +361 -0
- package/src/.github/skills/scientific-academic-writing/assets/acs_article.md +199 -0
- package/src/.github/skills/scientific-academic-writing/assets/elsevier_article.md +244 -0
- package/src/.github/skills/scientific-academic-writing/assets/ieee_transactions.md +212 -0
- package/src/.github/skills/scientific-academic-writing/assets/imrad_standard.md +181 -0
- package/src/.github/skills/scientific-academic-writing/assets/nature_article.md +179 -0
- package/src/.github/skills/scientific-academic-writing/assets/qiita_technical_article.md +385 -0
- package/src/.github/skills/scientific-academic-writing/assets/science_research_article.md +169 -0
- package/src/.github/skills/scientific-bioinformatics/SKILL.md +220 -0
- package/src/.github/skills/scientific-biosignal-processing/SKILL.md +357 -0
- package/src/.github/skills/scientific-causal-inference/SKILL.md +347 -0
- package/src/.github/skills/scientific-cheminformatics/SKILL.md +196 -0
- package/src/.github/skills/scientific-data-preprocessing/SKILL.md +413 -0
- package/src/.github/skills/scientific-data-simulation/SKILL.md +244 -0
- package/src/.github/skills/scientific-doe/SKILL.md +360 -0
- package/src/.github/skills/scientific-eda-correlation/SKILL.md +141 -0
- package/src/.github/skills/scientific-feature-importance/SKILL.md +208 -0
- package/src/.github/skills/scientific-image-analysis/SKILL.md +310 -0
- package/src/.github/skills/scientific-materials-characterization/SKILL.md +368 -0
- package/src/.github/skills/scientific-meta-analysis/SKILL.md +352 -0
- package/src/.github/skills/scientific-metabolomics/SKILL.md +326 -0
- package/src/.github/skills/scientific-ml-classification/SKILL.md +265 -0
- package/src/.github/skills/scientific-ml-regression/SKILL.md +215 -0
- package/src/.github/skills/scientific-multi-omics/SKILL.md +303 -0
- package/src/.github/skills/scientific-network-analysis/SKILL.md +257 -0
- package/src/.github/skills/scientific-pca-tsne/SKILL.md +235 -0
- package/src/.github/skills/scientific-pipeline-scaffold/SKILL.md +331 -0
- package/src/.github/skills/scientific-process-optimization/SKILL.md +215 -0
- package/src/.github/skills/scientific-publication-figures/SKILL.md +208 -0
- package/src/.github/skills/scientific-sequence-analysis/SKILL.md +389 -0
- package/src/.github/skills/scientific-spectral-signal/SKILL.md +227 -0
- package/src/.github/skills/scientific-statistical-testing/SKILL.md +240 -0
- package/src/.github/skills/scientific-survival-clinical/SKILL.md +239 -0
- package/src/.github/skills/scientific-time-series/SKILL.md +291 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-image-analysis
|
|
3
|
+
description: |
|
|
4
|
+
科学画像解析スキル。顕微鏡画像のセグメンテーション(Otsu/Watershed/Felzenszwalb)、
|
|
5
|
+
粒径分布解析、形態計測(面積・周囲長・真円度・アスペクト比)、テクスチャ解析
|
|
6
|
+
(GLCM/LBP)、強度プロファイル、マルチチャネル蛍光画像合成の解析テンプレート。
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Scientific Image Analysis
|
|
10
|
+
|
|
11
|
+
光学顕微鏡(SEM / TEM / 蛍光)や医用画像データの定量解析パイプライン。
|
|
12
|
+
画像前処理→セグメンテーション→形態計測→統計解析の標準ワークフローを提供する。
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- 顕微鏡画像の粒子・構造のセグメンテーションが必要なとき
|
|
17
|
+
- 粒径分布・形態パラメータ(面積、真円度など)を定量化するとき
|
|
18
|
+
- テクスチャ特徴量(GLCM / LBP)を抽出するとき
|
|
19
|
+
- 蛍光画像のマルチチャネル合成・強度定量化が必要なとき
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
## 1. 画像読み込み・前処理
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
import numpy as np
|
|
29
|
+
import matplotlib.pyplot as plt
|
|
30
|
+
from skimage import io, filters, morphology, measure, exposure, color
|
|
31
|
+
from skimage.segmentation import watershed, felzenszwalb
|
|
32
|
+
from scipy import ndimage
|
|
33
|
+
|
|
34
|
+
def load_and_preprocess(filepath, target_size=None):
|
|
35
|
+
"""
|
|
36
|
+
画像の読み込みと前処理。
|
|
37
|
+
|
|
38
|
+
Steps:
|
|
39
|
+
1. グレースケール変換
|
|
40
|
+
2. コントラスト強調 (CLAHE)
|
|
41
|
+
3. ノイズ除去 (Gaussian)
|
|
42
|
+
"""
|
|
43
|
+
img = io.imread(filepath)
|
|
44
|
+
|
|
45
|
+
if img.ndim == 3:
|
|
46
|
+
gray = color.rgb2gray(img)
|
|
47
|
+
else:
|
|
48
|
+
gray = img.astype(float)
|
|
49
|
+
|
|
50
|
+
# CLAHE (Contrast Limited Adaptive Histogram Equalization)
|
|
51
|
+
enhanced = exposure.equalize_adapthist(gray, clip_limit=0.03)
|
|
52
|
+
|
|
53
|
+
# ガウシアンノイズ除去
|
|
54
|
+
denoised = filters.gaussian(enhanced, sigma=1)
|
|
55
|
+
|
|
56
|
+
if target_size is not None:
|
|
57
|
+
from skimage.transform import resize
|
|
58
|
+
denoised = resize(denoised, target_size, anti_aliasing=True)
|
|
59
|
+
|
|
60
|
+
return img, gray, denoised
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 2. セグメンテーション
|
|
64
|
+
|
|
65
|
+
### 2.1 Otsu + 形態演算
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
def otsu_segmentation(image, min_size=50, closing_disk=3):
|
|
69
|
+
"""
|
|
70
|
+
Otsu 閾値 + 形態学的クリーニングによるバイナリセグメンテーション。
|
|
71
|
+
"""
|
|
72
|
+
threshold = filters.threshold_otsu(image)
|
|
73
|
+
binary = image > threshold
|
|
74
|
+
|
|
75
|
+
# 形態学的クリーニング
|
|
76
|
+
binary = morphology.binary_closing(binary, morphology.disk(closing_disk))
|
|
77
|
+
binary = morphology.remove_small_objects(binary, min_size=min_size)
|
|
78
|
+
binary = ndimage.binary_fill_holes(binary)
|
|
79
|
+
|
|
80
|
+
# ラベリング
|
|
81
|
+
labels = measure.label(binary)
|
|
82
|
+
|
|
83
|
+
return binary, labels, threshold
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 2.2 Watershed セグメンテーション
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from skimage.feature import peak_local_max
|
|
90
|
+
|
|
91
|
+
def watershed_segmentation(image, min_distance=10, footprint_size=3):
|
|
92
|
+
"""
|
|
93
|
+
Watershed による接触粒子の分離セグメンテーション。
|
|
94
|
+
"""
|
|
95
|
+
threshold = filters.threshold_otsu(image)
|
|
96
|
+
binary = image > threshold
|
|
97
|
+
binary = ndimage.binary_fill_holes(binary)
|
|
98
|
+
|
|
99
|
+
# 距離変換
|
|
100
|
+
distance = ndimage.distance_transform_edt(binary)
|
|
101
|
+
|
|
102
|
+
# ローカルマキシマ
|
|
103
|
+
coords = peak_local_max(distance, min_distance=min_distance,
|
|
104
|
+
labels=binary)
|
|
105
|
+
mask = np.zeros(distance.shape, dtype=bool)
|
|
106
|
+
mask[tuple(coords.T)] = True
|
|
107
|
+
markers = measure.label(mask)
|
|
108
|
+
|
|
109
|
+
# Watershed
|
|
110
|
+
labels = watershed(-distance, markers, mask=binary)
|
|
111
|
+
|
|
112
|
+
return labels, distance
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## 3. 形態計測
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
def morphometric_analysis(labels, pixel_size_um=1.0):
|
|
119
|
+
"""
|
|
120
|
+
ラベル画像から各オブジェクトの形態パラメータを計測する。
|
|
121
|
+
|
|
122
|
+
計測項目:
|
|
123
|
+
- area: 面積 (μm²)
|
|
124
|
+
- perimeter: 周囲長 (μm)
|
|
125
|
+
- equivalent_diameter: 等価円直径 (μm)
|
|
126
|
+
- circularity: 真円度 4π·A/P²
|
|
127
|
+
- aspect_ratio: アスペクト比 (major/minor axis)
|
|
128
|
+
- solidity: 充填率 (area/convex_area)
|
|
129
|
+
- eccentricity: 離心率
|
|
130
|
+
"""
|
|
131
|
+
import pandas as pd
|
|
132
|
+
|
|
133
|
+
props = measure.regionprops(labels)
|
|
134
|
+
records = []
|
|
135
|
+
|
|
136
|
+
for p in props:
|
|
137
|
+
area = p.area * (pixel_size_um ** 2)
|
|
138
|
+
perimeter = p.perimeter * pixel_size_um
|
|
139
|
+
eq_diameter = p.equivalent_diameter * pixel_size_um
|
|
140
|
+
circularity = (4 * np.pi * p.area) / (p.perimeter**2 + 1e-10)
|
|
141
|
+
aspect_ratio = p.major_axis_length / (p.minor_axis_length + 1e-10)
|
|
142
|
+
|
|
143
|
+
records.append({
|
|
144
|
+
"label": p.label,
|
|
145
|
+
"area_um2": area,
|
|
146
|
+
"perimeter_um": perimeter,
|
|
147
|
+
"equivalent_diameter_um": eq_diameter,
|
|
148
|
+
"circularity": circularity,
|
|
149
|
+
"aspect_ratio": aspect_ratio,
|
|
150
|
+
"solidity": p.solidity,
|
|
151
|
+
"eccentricity": p.eccentricity,
|
|
152
|
+
"centroid_y": p.centroid[0],
|
|
153
|
+
"centroid_x": p.centroid[1],
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
return pd.DataFrame(records)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 4. 粒径分布
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
def particle_size_distribution(morpho_df, diameter_col="equivalent_diameter_um",
|
|
163
|
+
bins=30, figsize=(10, 6)):
|
|
164
|
+
"""
|
|
165
|
+
粒径分布のヒストグラムと統計量を算出する。
|
|
166
|
+
|
|
167
|
+
出力:
|
|
168
|
+
- ヒストグラム + カーネル密度
|
|
169
|
+
- D10, D50 (中央値), D90
|
|
170
|
+
- 平均, 標準偏差, 変動係数 CV
|
|
171
|
+
"""
|
|
172
|
+
diameters = morpho_df[diameter_col].values
|
|
173
|
+
|
|
174
|
+
d10 = np.percentile(diameters, 10)
|
|
175
|
+
d50 = np.percentile(diameters, 50)
|
|
176
|
+
d90 = np.percentile(diameters, 90)
|
|
177
|
+
span = (d90 - d10) / d50
|
|
178
|
+
|
|
179
|
+
stats = {
|
|
180
|
+
"count": len(diameters),
|
|
181
|
+
"mean_um": np.mean(diameters),
|
|
182
|
+
"std_um": np.std(diameters),
|
|
183
|
+
"cv_pct": np.std(diameters) / np.mean(diameters) * 100,
|
|
184
|
+
"d10_um": d10,
|
|
185
|
+
"d50_um": d50,
|
|
186
|
+
"d90_um": d90,
|
|
187
|
+
"span": span,
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
fig, ax = plt.subplots(figsize=figsize)
|
|
191
|
+
ax.hist(diameters, bins=bins, density=True, alpha=0.7, color="steelblue",
|
|
192
|
+
edgecolor="black", linewidth=0.5)
|
|
193
|
+
|
|
194
|
+
# KDE
|
|
195
|
+
from scipy.stats import gaussian_kde
|
|
196
|
+
kde = gaussian_kde(diameters)
|
|
197
|
+
x_range = np.linspace(diameters.min(), diameters.max(), 200)
|
|
198
|
+
ax.plot(x_range, kde(x_range), "r-", linewidth=2, label="KDE")
|
|
199
|
+
|
|
200
|
+
# D10/D50/D90 線
|
|
201
|
+
for d, label in [(d10, "D10"), (d50, "D50"), (d90, "D90")]:
|
|
202
|
+
ax.axvline(d, color="gray", linestyle="--", alpha=0.7)
|
|
203
|
+
ax.text(d, ax.get_ylim()[1]*0.95, f" {label}={d:.1f}", fontsize=9)
|
|
204
|
+
|
|
205
|
+
ax.set_xlabel("Diameter (μm)")
|
|
206
|
+
ax.set_ylabel("Density")
|
|
207
|
+
ax.set_title("Particle Size Distribution", fontweight="bold")
|
|
208
|
+
ax.legend()
|
|
209
|
+
plt.tight_layout()
|
|
210
|
+
plt.savefig("figures/particle_size_distribution.png", dpi=300,
|
|
211
|
+
bbox_inches="tight")
|
|
212
|
+
plt.close()
|
|
213
|
+
|
|
214
|
+
return stats
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## 5. テクスチャ解析 (GLCM)
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
from skimage.feature import graycomatrix, graycoprops
|
|
221
|
+
|
|
222
|
+
def glcm_texture_features(image, distances=[1, 3, 5], angles=[0, np.pi/4,
|
|
223
|
+
np.pi/2, 3*np.pi/4], levels=256):
|
|
224
|
+
"""
|
|
225
|
+
GLCM (Gray-Level Co-occurrence Matrix) テクスチャ特徴量を抽出する。
|
|
226
|
+
|
|
227
|
+
Features: contrast, dissimilarity, homogeneity, energy, correlation, ASM
|
|
228
|
+
"""
|
|
229
|
+
img_uint8 = (image * 255).astype(np.uint8) if image.max() <= 1 else image.astype(np.uint8)
|
|
230
|
+
|
|
231
|
+
glcm = graycomatrix(img_uint8, distances=distances, angles=angles,
|
|
232
|
+
levels=levels, symmetric=True, normed=True)
|
|
233
|
+
|
|
234
|
+
features = {}
|
|
235
|
+
for prop in ["contrast", "dissimilarity", "homogeneity", "energy",
|
|
236
|
+
"correlation", "ASM"]:
|
|
237
|
+
values = graycoprops(glcm, prop)
|
|
238
|
+
features[f"{prop}_mean"] = values.mean()
|
|
239
|
+
features[f"{prop}_std"] = values.std()
|
|
240
|
+
|
|
241
|
+
return features
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## 6. 蛍光マルチチャネル合成
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
def merge_fluorescence_channels(channels, colors=None, figsize=(10, 10)):
|
|
248
|
+
"""
|
|
249
|
+
蛍光顕微鏡のマルチチャネル画像を合成する。
|
|
250
|
+
|
|
251
|
+
Parameters:
|
|
252
|
+
channels: dict {"DAPI": array, "GFP": array, "RFP": array}
|
|
253
|
+
colors: dict {"DAPI": [0,0,1], "GFP": [0,1,0], "RFP": [1,0,0]}
|
|
254
|
+
"""
|
|
255
|
+
if colors is None:
|
|
256
|
+
colors = {"DAPI": [0, 0, 1], "GFP": [0, 1, 0], "RFP": [1, 0, 0],
|
|
257
|
+
"Cy5": [1, 0, 1]}
|
|
258
|
+
|
|
259
|
+
ch_names = list(channels.keys())
|
|
260
|
+
shape = list(channels.values())[0].shape
|
|
261
|
+
merged = np.zeros((*shape, 3))
|
|
262
|
+
|
|
263
|
+
n = len(ch_names) + 1
|
|
264
|
+
fig, axes = plt.subplots(1, n, figsize=(5*n, 5))
|
|
265
|
+
|
|
266
|
+
for i, (name, img) in enumerate(channels.items()):
|
|
267
|
+
# 正規化
|
|
268
|
+
norm_img = (img - img.min()) / (img.max() - img.min() + 1e-10)
|
|
269
|
+
|
|
270
|
+
# 個別チャネル表示
|
|
271
|
+
ch_color = np.array(colors.get(name, [1, 1, 1]))
|
|
272
|
+
colored = norm_img[:, :, np.newaxis] * ch_color
|
|
273
|
+
axes[i].imshow(np.clip(colored, 0, 1))
|
|
274
|
+
axes[i].set_title(name, fontweight="bold")
|
|
275
|
+
axes[i].axis("off")
|
|
276
|
+
|
|
277
|
+
# マージ画像に加算
|
|
278
|
+
merged += colored
|
|
279
|
+
|
|
280
|
+
# 合成画像
|
|
281
|
+
axes[-1].imshow(np.clip(merged, 0, 1))
|
|
282
|
+
axes[-1].set_title("Merged", fontweight="bold")
|
|
283
|
+
axes[-1].axis("off")
|
|
284
|
+
|
|
285
|
+
plt.tight_layout()
|
|
286
|
+
plt.savefig("figures/fluorescence_merged.png", dpi=300, bbox_inches="tight")
|
|
287
|
+
plt.close()
|
|
288
|
+
|
|
289
|
+
return np.clip(merged, 0, 1)
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## References
|
|
293
|
+
|
|
294
|
+
### Output Files
|
|
295
|
+
|
|
296
|
+
| ファイル | 形式 |
|
|
297
|
+
|---|---|
|
|
298
|
+
| `results/morphometric_data.csv` | CSV |
|
|
299
|
+
| `results/particle_size_stats.csv` | CSV |
|
|
300
|
+
| `results/glcm_texture_features.csv` | CSV |
|
|
301
|
+
| `figures/segmentation_result.png` | PNG |
|
|
302
|
+
| `figures/particle_size_distribution.png` | PNG |
|
|
303
|
+
| `figures/fluorescence_merged.png` | PNG |
|
|
304
|
+
|
|
305
|
+
#### 依存パッケージ
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
scikit-image>=0.21
|
|
309
|
+
scipy>=1.10
|
|
310
|
+
```
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-materials-characterization
|
|
3
|
+
description: |
|
|
4
|
+
薄膜・材料キャラクタリゼーション解析のスキル。Thornton-Anders 構造ゾーンモデル(SZM)、
|
|
5
|
+
XRD 結晶子サイズ解析(Scherrer 方程式)、Williamson-Hall プロット、多技法融合データ解析、
|
|
6
|
+
PSP フレームワーク設計を行う際に使用。Scientific Skills Exp-13 で確立したパターン。
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Scientific Materials Characterization
|
|
10
|
+
|
|
11
|
+
薄膜工学・材料科学における構造キャラクタリゼーション解析パイプラインスキル。
|
|
12
|
+
XRD、AFM、四探針法、UV-Vis などの測定データを統合し、Process-Structure-Property
|
|
13
|
+
(PSP)の因果連鎖を定量化する。
|
|
14
|
+
|
|
15
|
+
## When to Use
|
|
16
|
+
|
|
17
|
+
- 薄膜の成膜条件と膜特性の相関を解析したいとき
|
|
18
|
+
- XRD データから結晶子サイズ・格子歪を解析したいとき
|
|
19
|
+
- Thornton-Anders 構造ゾーンモデルにデータをマッピングしたいとき
|
|
20
|
+
- 多技法(XRD + AFM + 電気 + 光学)データを統合した解析
|
|
21
|
+
- PSP フレームワーク(Process → Structure → Property)
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
## 1. 材料定義テンプレート
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
# 材料物性定数辞書
|
|
29
|
+
MATERIAL_PROPERTIES = {
|
|
30
|
+
"ZnO": {"Tm_K": 2248, "Eg_eV": 3.37, "type": "TCO", "crystal": "wurtzite"},
|
|
31
|
+
"ITO": {"Tm_K": 2200, "Eg_eV": 3.70, "type": "TCO", "crystal": "cubic"},
|
|
32
|
+
"Al2O3": {"Tm_K": 2345, "Eg_eV": 8.80, "type": "dielectric", "crystal": "corundum"},
|
|
33
|
+
"HfO2": {"Tm_K": 3031, "Eg_eV": 5.80, "type": "dielectric", "crystal": "monoclinic"},
|
|
34
|
+
"TiO2": {"Tm_K": 2116, "Eg_eV": 3.20, "type": "functional", "crystal": "rutile"},
|
|
35
|
+
"SiO2": {"Tm_K": 1986, "Eg_eV": 8.90, "type": "dielectric", "crystal": "amorphous"},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# XRD 主要ピーク位置 (2θ, Cu-Kα)
|
|
39
|
+
XRD_PEAKS = {
|
|
40
|
+
"ZnO": {"(100)": 31.8, "(002)": 34.4, "(101)": 36.3},
|
|
41
|
+
"ITO": {"(222)": 30.6, "(400)": 35.5, "(440)": 51.0},
|
|
42
|
+
"TiO2": {"(110)": 27.4, "(101)": 25.3, "(200)": 36.1},
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 2. 相同温度と構造ゾーンモデル(Thornton-Anders)
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
import numpy as np
|
|
50
|
+
import matplotlib.pyplot as plt
|
|
51
|
+
import matplotlib.patches as patches
|
|
52
|
+
|
|
53
|
+
def calculate_homologous_temperature(T_substrate_C, T_melt_K):
|
|
54
|
+
"""
|
|
55
|
+
相同温度 T/Tm を算出する。
|
|
56
|
+
T_substrate_C: 基板温度 (°C)
|
|
57
|
+
T_melt_K: 融点 (K)
|
|
58
|
+
"""
|
|
59
|
+
return (T_substrate_C + 273.15) / T_melt_K
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def structure_zone_model(df, T_sub_col, material_col, materials_dict,
|
|
63
|
+
crystallite_col=None, figsize=(12, 8)):
|
|
64
|
+
"""
|
|
65
|
+
Thornton-Anders 構造ゾーンモデルにデータをマッピングする。
|
|
66
|
+
|
|
67
|
+
ゾーン境界:
|
|
68
|
+
- Zone 1: T/Tm < 0.15 (繊維状 / アモルファス)
|
|
69
|
+
- Zone T: 0.15 ≤ T/Tm < 0.30 (遷移帯 / 緻密微結晶)
|
|
70
|
+
- Zone 2: 0.30 ≤ T/Tm < 0.50 (柱状結晶)
|
|
71
|
+
- Zone 3: T/Tm ≥ 0.50 (等軸粒)
|
|
72
|
+
"""
|
|
73
|
+
df = df.copy()
|
|
74
|
+
|
|
75
|
+
# 相同温度を算出
|
|
76
|
+
df["T_homologous"] = df.apply(
|
|
77
|
+
lambda row: calculate_homologous_temperature(
|
|
78
|
+
row[T_sub_col],
|
|
79
|
+
materials_dict[row[material_col]]["Tm_K"]
|
|
80
|
+
), axis=1
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# ゾーン分類
|
|
84
|
+
def classify_zone(T_Tm):
|
|
85
|
+
if T_Tm < 0.15:
|
|
86
|
+
return "Zone 1"
|
|
87
|
+
elif T_Tm < 0.30:
|
|
88
|
+
return "Zone T"
|
|
89
|
+
elif T_Tm < 0.50:
|
|
90
|
+
return "Zone 2"
|
|
91
|
+
else:
|
|
92
|
+
return "Zone 3"
|
|
93
|
+
|
|
94
|
+
df["Structure_Zone"] = df["T_homologous"].apply(classify_zone)
|
|
95
|
+
|
|
96
|
+
# ──── 可視化 ────
|
|
97
|
+
fig, ax = plt.subplots(figsize=figsize)
|
|
98
|
+
|
|
99
|
+
zone_colors = {
|
|
100
|
+
"Zone 1": "#FFE0B2", # 薄橙
|
|
101
|
+
"Zone T": "#C8E6C9", # 薄緑
|
|
102
|
+
"Zone 2": "#BBDEFB", # 薄青
|
|
103
|
+
"Zone 3": "#F8BBD0", # 薄桃
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
# ゾーン背景
|
|
107
|
+
boundaries = [0, 0.15, 0.30, 0.50, 0.80]
|
|
108
|
+
zone_names = ["Zone 1\n(Fibrous)", "Zone T\n(Transition)",
|
|
109
|
+
"Zone 2\n(Columnar)", "Zone 3\n(Equiaxed)"]
|
|
110
|
+
for i, (b_start, b_end) in enumerate(zip(boundaries[:-1], boundaries[1:])):
|
|
111
|
+
rect = patches.Rectangle(
|
|
112
|
+
(b_start, 0), b_end - b_start, 1,
|
|
113
|
+
linewidth=0, facecolor=list(zone_colors.values())[i], alpha=0.3
|
|
114
|
+
)
|
|
115
|
+
ax.add_patch(rect)
|
|
116
|
+
ax.text((b_start + b_end) / 2, 0.95, zone_names[i],
|
|
117
|
+
ha="center", va="top", fontsize=9, fontweight="bold", alpha=0.6)
|
|
118
|
+
|
|
119
|
+
# 材料別プロット
|
|
120
|
+
unique_mats = df[material_col].unique()
|
|
121
|
+
colors = plt.cm.Set2(np.linspace(0, 1, len(unique_mats)))
|
|
122
|
+
|
|
123
|
+
for color, mat in zip(colors, unique_mats):
|
|
124
|
+
mask = df[material_col] == mat
|
|
125
|
+
subset = df[mask]
|
|
126
|
+
|
|
127
|
+
# 正規化粒子エネルギー(出力 / 圧力の比のプロキシ)
|
|
128
|
+
if "Power" in df.columns and "Working_Pressure" in df.columns:
|
|
129
|
+
y_val = subset["Power"] / (subset["Working_Pressure"] * 100 + 1)
|
|
130
|
+
y_val = (y_val - y_val.min()) / (y_val.max() - y_val.min() + 1e-10)
|
|
131
|
+
else:
|
|
132
|
+
y_val = np.random.uniform(0.3, 0.7, mask.sum())
|
|
133
|
+
|
|
134
|
+
sizes = 50
|
|
135
|
+
if crystallite_col and crystallite_col in df.columns:
|
|
136
|
+
cs = subset[crystallite_col].values
|
|
137
|
+
sizes = 30 + (cs - cs.min()) / (cs.max() - cs.min() + 1e-10) * 200
|
|
138
|
+
|
|
139
|
+
ax.scatter(subset["T_homologous"], y_val,
|
|
140
|
+
s=sizes, c=[color], label=mat,
|
|
141
|
+
alpha=0.7, edgecolors="black", linewidth=0.5)
|
|
142
|
+
|
|
143
|
+
ax.set_xlabel("Homologous Temperature T/Tₘ", fontsize=12)
|
|
144
|
+
ax.set_ylabel("Normalized Particle Energy", fontsize=12)
|
|
145
|
+
ax.set_title("Thornton-Anders Structure Zone Model", fontsize=14,
|
|
146
|
+
fontweight="bold")
|
|
147
|
+
ax.set_xlim(0, max(df["T_homologous"].max() * 1.1, 0.6))
|
|
148
|
+
ax.set_ylim(0, 1)
|
|
149
|
+
ax.legend(title="Material", bbox_to_anchor=(1.05, 1))
|
|
150
|
+
|
|
151
|
+
# ゾーン境界線
|
|
152
|
+
for b in [0.15, 0.30, 0.50]:
|
|
153
|
+
ax.axvline(b, color="gray", linestyle="--", linewidth=1, alpha=0.5)
|
|
154
|
+
|
|
155
|
+
plt.tight_layout()
|
|
156
|
+
plt.savefig("figures/structure_zone_model.png", dpi=300, bbox_inches="tight")
|
|
157
|
+
plt.close()
|
|
158
|
+
|
|
159
|
+
# ゾーン統計
|
|
160
|
+
zone_stats = df.groupby("Structure_Zone").agg(
|
|
161
|
+
Count=("Structure_Zone", "size"),
|
|
162
|
+
Mean_T_Tm=("T_homologous", "mean"),
|
|
163
|
+
)
|
|
164
|
+
if crystallite_col:
|
|
165
|
+
zone_stats["Mean_Crystallite"] = df.groupby("Structure_Zone")[crystallite_col].mean()
|
|
166
|
+
zone_stats.to_csv("results/structure_zone_statistics.csv")
|
|
167
|
+
|
|
168
|
+
return df, zone_stats
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## 3. XRD 結晶子サイズ解析(Scherrer 方程式)
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
def scherrer_crystallite_size(beta_rad, two_theta_deg, K=0.9, wavelength_nm=0.15406):
|
|
175
|
+
"""
|
|
176
|
+
Scherrer 方程式: D = Kλ / (β cos θ)
|
|
177
|
+
|
|
178
|
+
Parameters:
|
|
179
|
+
beta_rad: 半値全幅 FWHM (ラジアン)
|
|
180
|
+
two_theta_deg: ブラッグ角 2θ (度)
|
|
181
|
+
K: 形状因子 (通常 0.9)
|
|
182
|
+
wavelength_nm: X 線波長 (nm, Cu-Kα = 0.15406)
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
結晶子サイズ D (nm)
|
|
186
|
+
"""
|
|
187
|
+
theta_rad = np.radians(two_theta_deg / 2)
|
|
188
|
+
D = (K * wavelength_nm) / (beta_rad * np.cos(theta_rad))
|
|
189
|
+
return D
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def williamson_hall_analysis(two_theta_list, fwhm_list, wavelength_nm=0.15406):
|
|
193
|
+
"""
|
|
194
|
+
Williamson-Hall プロット: β cos θ = Kλ/D + 4ε sin θ
|
|
195
|
+
|
|
196
|
+
FWHM のブロードニングを結晶子サイズ効果と格子歪み効果に分離する。
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
D: 結晶子サイズ (nm)
|
|
200
|
+
epsilon: 格子歪み (%)
|
|
201
|
+
"""
|
|
202
|
+
theta_rad = np.radians(np.array(two_theta_list) / 2)
|
|
203
|
+
beta_rad = np.array(fwhm_list)
|
|
204
|
+
|
|
205
|
+
x = 4 * np.sin(theta_rad)
|
|
206
|
+
y = beta_rad * np.cos(theta_rad)
|
|
207
|
+
|
|
208
|
+
# 線形回帰: y = intercept + slope * x
|
|
209
|
+
from scipy.stats import linregress
|
|
210
|
+
slope, intercept, r_value, p_value, std_err = linregress(x, y)
|
|
211
|
+
|
|
212
|
+
D = (0.9 * wavelength_nm) / intercept if intercept > 0 else np.nan
|
|
213
|
+
epsilon = slope * 100 # %
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
"crystallite_size_nm": D,
|
|
217
|
+
"lattice_strain_pct": epsilon,
|
|
218
|
+
"r_squared": r_value ** 2,
|
|
219
|
+
"p_value": p_value,
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## 4. 配向度 TC(hkl) の計算
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
def texture_coefficient(I_measured, I_reference):
|
|
227
|
+
"""
|
|
228
|
+
配向度 Texture Coefficient TC(hkl) を計算する。
|
|
229
|
+
|
|
230
|
+
TC(hkl) = [I(hkl)/I₀(hkl)] / [(1/N) Σ I(hkl)/I₀(hkl)]
|
|
231
|
+
|
|
232
|
+
TC = 1: ランダム配向
|
|
233
|
+
TC > 1: 優先配向
|
|
234
|
+
TC < 1: 劣位配向
|
|
235
|
+
|
|
236
|
+
Parameters:
|
|
237
|
+
I_measured: dict {(hkl): intensity} — 測定ピーク強度
|
|
238
|
+
I_reference: dict {(hkl): intensity} — ICDD PDF カード参照強度
|
|
239
|
+
"""
|
|
240
|
+
ratios = {}
|
|
241
|
+
for hkl in I_measured:
|
|
242
|
+
if hkl in I_reference and I_reference[hkl] > 0:
|
|
243
|
+
ratios[hkl] = I_measured[hkl] / I_reference[hkl]
|
|
244
|
+
|
|
245
|
+
N = len(ratios)
|
|
246
|
+
if N == 0:
|
|
247
|
+
return {}
|
|
248
|
+
|
|
249
|
+
mean_ratio = np.mean(list(ratios.values()))
|
|
250
|
+
|
|
251
|
+
tc = {hkl: ratio / mean_ratio for hkl, ratio in ratios.items()}
|
|
252
|
+
return tc
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## 5. 膜応力解析(Stoney 方程式)
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
def stoney_film_stress(R_before_m, R_after_m, E_substrate_Pa,
|
|
259
|
+
nu_substrate, t_substrate_m, t_film_m):
|
|
260
|
+
"""
|
|
261
|
+
Stoney 方程式: σ = (Es × ts²) / (6(1-νs) × tf) × (1/R_after - 1/R_before)
|
|
262
|
+
|
|
263
|
+
曲率変化から膜応力を算出する。
|
|
264
|
+
|
|
265
|
+
Parameters:
|
|
266
|
+
R_before_m: 成膜前の曲率半径 (m)
|
|
267
|
+
R_after_m: 成膜後の曲率半径 (m)
|
|
268
|
+
E_substrate_Pa: 基板のヤング率 (Pa)
|
|
269
|
+
nu_substrate: 基板のポアソン比
|
|
270
|
+
t_substrate_m: 基板厚 (m)
|
|
271
|
+
t_film_m: 膜厚 (m)
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
膜応力 σ (Pa) — 正:引張、負:圧縮
|
|
275
|
+
"""
|
|
276
|
+
curvature_change = (1 / R_after_m) - (1 / R_before_m)
|
|
277
|
+
biaxial_modulus = E_substrate_Pa / (1 - nu_substrate)
|
|
278
|
+
sigma = (biaxial_modulus * t_substrate_m**2 * curvature_change) / (6 * t_film_m)
|
|
279
|
+
return sigma
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
# Si(100) 基板の標準定数
|
|
283
|
+
SI_SUBSTRATE = {
|
|
284
|
+
"E_Pa": 130.2e9, # ヤング率
|
|
285
|
+
"nu": 0.279, # ポアソン比
|
|
286
|
+
"t_m": 525e-6, # 標準ウエハ厚 525 μm
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## 6. 多技法融合データ統合
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
def merge_characterization_data(xrd_df, afm_df, electrical_df, optical_df,
|
|
294
|
+
sample_id_col="Sample_ID"):
|
|
295
|
+
"""
|
|
296
|
+
複数の測定手法のデータをサンプル ID で統合する。
|
|
297
|
+
|
|
298
|
+
XRD → 結晶子サイズ, 配向度, 格子歪
|
|
299
|
+
AFM → 表面粗さ Ra, Rq
|
|
300
|
+
電気 → 比抵抗, シート抵抗
|
|
301
|
+
光学 → 透過率, バンドギャップ
|
|
302
|
+
"""
|
|
303
|
+
merged = xrd_df.copy()
|
|
304
|
+
for df in [afm_df, electrical_df, optical_df]:
|
|
305
|
+
if df is not None and sample_id_col in df.columns:
|
|
306
|
+
merged = merged.merge(df, on=sample_id_col, how="left",
|
|
307
|
+
suffixes=("", "_dup"))
|
|
308
|
+
# 重複カラムを除去
|
|
309
|
+
dup_cols = [c for c in merged.columns if c.endswith("_dup")]
|
|
310
|
+
merged.drop(columns=dup_cols, inplace=True)
|
|
311
|
+
|
|
312
|
+
return merged
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def tauc_plot_bandgap(wavelength_nm, transmittance_pct, thickness_nm,
|
|
316
|
+
n_exponent=2, figsize=(8, 6)):
|
|
317
|
+
"""
|
|
318
|
+
Tauc プロットからバンドギャップを推定する。
|
|
319
|
+
|
|
320
|
+
(αhν)^(1/n) vs hν のプロットの線形外挿。
|
|
321
|
+
n=2: 直接遷移, n=0.5: 間接遷移
|
|
322
|
+
|
|
323
|
+
Parameters:
|
|
324
|
+
wavelength_nm: 波長 (nm)
|
|
325
|
+
transmittance_pct: 透過率 (%)
|
|
326
|
+
thickness_nm: 膜厚 (nm)
|
|
327
|
+
n_exponent: 遷移タイプ (2=直接, 0.5=間接)
|
|
328
|
+
"""
|
|
329
|
+
T = transmittance_pct / 100
|
|
330
|
+
alpha = -np.log(T + 1e-10) / (thickness_nm * 1e-7) # cm⁻¹
|
|
331
|
+
|
|
332
|
+
h = 6.626e-34 # Planck 定数 (J·s)
|
|
333
|
+
c = 3e8 # 光速 (m/s)
|
|
334
|
+
eV = 1.602e-19 # eV → J
|
|
335
|
+
|
|
336
|
+
energy_eV = (h * c) / (wavelength_nm * 1e-9) / eV # hν (eV)
|
|
337
|
+
tauc = (alpha * energy_eV) ** (1 / n_exponent)
|
|
338
|
+
|
|
339
|
+
fig, ax = plt.subplots(figsize=figsize)
|
|
340
|
+
ax.plot(energy_eV, tauc, "b-", linewidth=1.5)
|
|
341
|
+
ax.set_xlabel("Photon Energy hν (eV)")
|
|
342
|
+
ax.set_ylabel(f"(αhν)^(1/{n_exponent})")
|
|
343
|
+
ax.set_title("Tauc Plot", fontweight="bold")
|
|
344
|
+
plt.tight_layout()
|
|
345
|
+
plt.savefig("figures/tauc_plot.png", dpi=300, bbox_inches="tight")
|
|
346
|
+
plt.close()
|
|
347
|
+
|
|
348
|
+
return energy_eV, tauc
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## References
|
|
352
|
+
|
|
353
|
+
### Output Files
|
|
354
|
+
|
|
355
|
+
| ファイル | 形式 |
|
|
356
|
+
|---|---|
|
|
357
|
+
| `results/structure_zone_statistics.csv` | CSV |
|
|
358
|
+
| `results/xrd_analysis.csv` | CSV |
|
|
359
|
+
| `results/williamson_hall.csv` | CSV |
|
|
360
|
+
| `figures/structure_zone_model.png` | PNG |
|
|
361
|
+
| `figures/xrd_analysis.png` | PNG |
|
|
362
|
+
| `figures/tauc_plot.png` | PNG |
|
|
363
|
+
|
|
364
|
+
#### 参照実験
|
|
365
|
+
|
|
366
|
+
- **Exp-13**: 薄膜 PSP(Thornton-Anders SZM、XRD 結晶子サイズ、Stoney 膜応力)
|
|
367
|
+
- **Exp-12**: マテリアルサイエンスのプロセスデータ解析
|
|
368
|
+
- **Exp-11**: ARIM データポータルの材料データ活用
|