"""
X線反射率測定 (XRR) シミュレーションを行うためのスクリプト。
xrayutilities と pymatgen を使用して多層膜サンプルのXRRプロファイルを計算し、プロットします。
CIFファイルからの構造読み込みにも対応しています。
:doc:`atominf_xrayutilities_usage`
"""
# pip install xrayutilities pymatgen matplotlib numpy
import os
import numpy as np
import matplotlib.pyplot as plt
import xrayutilities as xu
from pymatgen.core import Composition, Structure
# ====== 単位変換 ======
[ドキュメント]
def gcm3_to_kgm3(rho):
"""
密度をg/cm³からkg/m³に変換します。
:param rho: 密度 (g/cm³)。
:type rho: float or int
:returns: 密度 (kg/m³)。
:rtype: float
"""
return float(rho) * 1000.0
[ドキュメント]
def nm_to_A(t_nm):
"""
厚さをナノメートル(nm)からオングストローム(A)に変換します。
:param t_nm: 厚さ (nm)。
:type t_nm: float or int
:returns: 厚さ (A)。
:rtype: float
"""
return float(t_nm) * 10.0
[ドキュメント]
def is_cif_path(s):
"""
与えられた文字列がCIFファイルのパスであるかを判定します。
文字列が `str` 型であり、`.cif` で終わる場合にTrueを返します(大文字・小文字を区別しない)。
:param s: 判定する文字列。
:type s: str
:returns: CIFファイルパスであればTrue、そうでなければFalse。
:rtype: bool
"""
return isinstance(s, str) and s.lower().endswith(".cif")
[ドキュメント]
def load_from_cif(path):
"""
指定されたCIFファイルから構造、化学式、密度を読み込みます。
`pymatgen` を使用してCIFファイルを解析し、`Structure`オブジェクト、
還元化学式、および密度 (g/cm³) を抽出します。
:param path: CIFファイルへのパス。
:type path: str
:returns:
- `structure` (`pymatgen.core.Structure`): 読み込まれた結晶構造オブジェクト。
- `formula` (str): 構造の還元化学式。
- `density` (float): 構造の密度 (g/cm³)。
:rtype: tuple[pymatgen.core.Structure, str, float]
"""
structure = Structure.from_file(path)
formula = structure.composition.reduced_formula
density = float(structure.density)
return structure, formula, density
[ドキュメント]
def main():
"""
多層膜のXRRシミュレーションを実行し、結果をプロットします。
層構造と基板の情報を定義し、それらから `xrayutilities` の `LayerStack` オブジェクトを構築します。
その後、XRRモデルを使用して反射率プロファイルを計算し、`matplotlib` で表示します。
CIFファイルからの層情報の読み込みもサポートしています。
"""
# ====== 層構造 ======
layer_stack = [
{"composition": "TiO2", "density_gcm3": 4.23, "thickness_nm": 50.0, "roughness_A": 0.5},
{"composition": "Al2O3", "density_gcm3": 3.95, "thickness_nm": 30.0, "roughness_A": 0.5},
{"composition": "SiO2", "density_gcm3": 2.20, "thickness_nm": 100.0, "roughness_A": 0.5},
# {"composition": "sample.cif", "density_gcm3": 0.0, "thickness_nm": 10.0, "roughness_A": 0.5},
]
substrate = {"composition": "Si", "density_gcm3": 2.33, "roughness_A": 0.5}
# ====== 表示:分子量 ======
print("各層の化学組成と分子量:")
for layer in layer_stack:
comp = layer["composition"]
if is_cif_path(comp):
_, formula, _ = load_from_cif(comp)
mw = Composition(formula).weight
print(f" {os.path.basename(comp)} ({formula}): {mw:.3f} g/mol")
else:
mw = Composition(comp).weight
print(f" {comp}: {mw:.3f} g/mol")
# ====== 基板 ======
sub_mat = xu.materials.Amorphous(substrate["composition"], gcm3_to_kgm3(substrate["density_gcm3"]))
stack = xu.simpack.Layer(sub_mat, float("inf"), roughness=substrate["roughness_A"])
# ====== 薄膜層 ======
for layer in layer_stack:
comp = layer["composition"]
rho = float(layer["density_gcm3"])
if is_cif_path(comp):
_, formula, rho_cif = load_from_cif(comp)
if rho <= 0.0:
rho = rho_cif
comp = formula
mat = xu.materials.Amorphous(comp, gcm3_to_kgm3(rho))
lay = xu.simpack.Layer(mat, nm_to_A(layer["thickness_nm"]), roughness=layer["roughness_A"])
stack = stack + lay
sample = xu.simpack.LayerStack("sample", stack)
# ====== XRR ======
model = xu.simpack.SpecularReflectivityModel(sample, energy="CuKa1")
alphai = np.linspace(0.05, 2.5, 2000)
R = model.simulate(alphai)
two_theta = 2 * alphai
plt.figure(figsize=(8, 5))
plt.semilogy(two_theta, R)
plt.xlabel("2θ (deg)")
plt.ylabel("Reflectivity")
plt.title("Multilayer XRR Simulation")
plt.grid(True, which="both")
plt.tight_layout()
plt.show()
if __name__ == "__main__":
main()