@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.
Files changed (38) hide show
  1. package/LICENCE +0 -0
  2. package/README.md +191 -0
  3. package/bin/satori.js +95 -0
  4. package/package.json +29 -0
  5. package/src/.github/skills/scientific-academic-writing/SKILL.md +361 -0
  6. package/src/.github/skills/scientific-academic-writing/assets/acs_article.md +199 -0
  7. package/src/.github/skills/scientific-academic-writing/assets/elsevier_article.md +244 -0
  8. package/src/.github/skills/scientific-academic-writing/assets/ieee_transactions.md +212 -0
  9. package/src/.github/skills/scientific-academic-writing/assets/imrad_standard.md +181 -0
  10. package/src/.github/skills/scientific-academic-writing/assets/nature_article.md +179 -0
  11. package/src/.github/skills/scientific-academic-writing/assets/qiita_technical_article.md +385 -0
  12. package/src/.github/skills/scientific-academic-writing/assets/science_research_article.md +169 -0
  13. package/src/.github/skills/scientific-bioinformatics/SKILL.md +220 -0
  14. package/src/.github/skills/scientific-biosignal-processing/SKILL.md +357 -0
  15. package/src/.github/skills/scientific-causal-inference/SKILL.md +347 -0
  16. package/src/.github/skills/scientific-cheminformatics/SKILL.md +196 -0
  17. package/src/.github/skills/scientific-data-preprocessing/SKILL.md +413 -0
  18. package/src/.github/skills/scientific-data-simulation/SKILL.md +244 -0
  19. package/src/.github/skills/scientific-doe/SKILL.md +360 -0
  20. package/src/.github/skills/scientific-eda-correlation/SKILL.md +141 -0
  21. package/src/.github/skills/scientific-feature-importance/SKILL.md +208 -0
  22. package/src/.github/skills/scientific-image-analysis/SKILL.md +310 -0
  23. package/src/.github/skills/scientific-materials-characterization/SKILL.md +368 -0
  24. package/src/.github/skills/scientific-meta-analysis/SKILL.md +352 -0
  25. package/src/.github/skills/scientific-metabolomics/SKILL.md +326 -0
  26. package/src/.github/skills/scientific-ml-classification/SKILL.md +265 -0
  27. package/src/.github/skills/scientific-ml-regression/SKILL.md +215 -0
  28. package/src/.github/skills/scientific-multi-omics/SKILL.md +303 -0
  29. package/src/.github/skills/scientific-network-analysis/SKILL.md +257 -0
  30. package/src/.github/skills/scientific-pca-tsne/SKILL.md +235 -0
  31. package/src/.github/skills/scientific-pipeline-scaffold/SKILL.md +331 -0
  32. package/src/.github/skills/scientific-process-optimization/SKILL.md +215 -0
  33. package/src/.github/skills/scientific-publication-figures/SKILL.md +208 -0
  34. package/src/.github/skills/scientific-sequence-analysis/SKILL.md +389 -0
  35. package/src/.github/skills/scientific-spectral-signal/SKILL.md +227 -0
  36. package/src/.github/skills/scientific-statistical-testing/SKILL.md +240 -0
  37. package/src/.github/skills/scientific-survival-clinical/SKILL.md +239 -0
  38. 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 データポータルの材料データ活用