xrd_fit.py ダウンロード/コピー
xrd_fit.py
xrd_fit.py
1"""
2X線回折(XRD)データ解析スクリプト
3
4概要:
5このスクリプトは、実験的に測定されたX線回折(XRD)パターンと、結晶構造情報ファイル(CIF)から計算された理論的なXRDパターンを比較・分析するためのツールです。
6主な機能として、パターンプロット、相関分析、オーバーラップチェック、およびLASSO回帰による混合相の定量フィッティングを提供します。
7
8詳細説明:
9本スクリプトは、様々なモードでXRDデータ解析を実行します。
10- `plot_all`: 実験XRDパターンと各CIF由来の理論XRDパターンを個別のグラフに表示します。
11- `plot_one`: 実験XRDパターンと各CIF由来の回折ピーク位置を一つのグラフに表示します。
12- `plot_one2`: 実験XRDパターンと各CIF由来の理論XRDパターンを一つのグラフに表示します。
13- `overwrap`: 異なるCIFパターン間のオーバーラップ(重なり)を評価します。
14- `CIFcorrelation`: CIFパターン間の相関係数を評価します。
15- `correlation`: 実験パターンとCIFパターン間の相関係数を評価します。
16- `fit`: LASSO回帰を用いて実験パターンを背景とCIFパターンでフィッティングし、各相の寄与を定量化します。
17スマアリング(ブロードニング)効果や背景処理もサポートしています。
18
19関連リンク:
20:doc:`xrd_fit_usage`
21"""
22
23import os
24import sys
25import glob
26import numpy as np
27from numpy import exp, log, sin, cos, tan, arcsin, arccos, arctan, pi
28from scipy.special import legendre
29from scipy.interpolate import interp1d
30from matplotlib import pyplot as plt
31import pandas as pd
32from sklearn.preprocessing import StandardScaler
33from sklearn.linear_model import Lasso
34from sklearn.metrics import mean_absolute_error, mean_squared_error
35
36
37from tklib.tkapplication import tkApplication
38from tklib.tkfile import tkFile
39from tklib.tkutils import getarg, getintarg, getfloatarg, pint, pfloat, split_file_path, replace_path
40from tklib.tkvariousdata import tkVariousData
41from tklib.tksci.tksci import Gaussian, Lorentzian, GaussLorentz
42from tklib.tksci.tkmatrix import make_matrix1, make_matrix2, make_matrix3
43from tklib.tkcrystal.tkxrd import Xray_wavelengths
44from tklib.tkgraphic.tkplotevent import tkPlotEvent
45
46
47# Xray_wavelengths
48# URL: https://github.com/materialsproject/pymatgen/blob/v2023.5.10/pymatgen/analysis/diffraction/xrd.py
49# 'CuKa', 'CuKa2', 'CuKa1', 'CuKb1', 'MoKa', 'MoKa2', 'MoKa1', 'MoKb1',
50# 'CrKa', 'CrKa2', 'CrKa1', 'CrKb1', 'FeKa', 'FeKa2', 'FeKa1', 'FeKb1', 'CoKa', 'CoKa2', 'CoKa1', 'CoKb1',
51# 'AgKa', 'AgKa2', 'AgKa1', 'AgKb1'
52
53
54
55usage_str = '''
56" (i) usage: python {} mode input_path cif_dir wavelength Q2min Q2max Q2step fwhm yscale BG_order LASSO_alpha".format(sys.argv[0])
57" ex: python {} plot_all {} {} {} {} {} {} {} {}".format(sys.argv[0], cparams.infile, cparams.wavelength, cparams.xmin, cparams.xmax, cparams.xstep, cparams.fwhm, cparams.yscale, cparams.BGorder, cparams.alpha)
58" ex: python {} plot_one {} {} {} {} {} {} {} {}".format(sys.argv[0], cparams.infile, cparams.wavelength, cparams.xmin, cparams.xmax, cparams.xstep, cparams.fwhm, cparams.yscale, cparams.BGorder, cparams.alpha)
59" ex: python {} plot_one2 {} {} {} {} {} {} {} {} {}".format(sys.argv[0], cparams.infile, cparams.wavelength, cparams.xmin, cparams.xmax, cparams.xstep, cparams.fwhm, cparams.yscale, cparams.BGorder, cparams.alpha)
60" ex: python {} fit {} {} {} {} {} {} {} {} {}".format(sys.argv[0], cparams.infile, cparams.wavelength, cparams.xmin, cparams.xmax, cparams.xstep, cparams.fwhm, cparams.yscale, cparams.BGorder, cparams.alpha)
61'''[1:-1]
62
63
64
65#================================
66# global parameters
67#================================
68module_names = []
69modules = []
70
71markers = ['o', 's', '+', 'x', 'D', 'v', '^', '<', '>', '8', 'h', 'H']
72colors = ['black', 'red', 'blue', 'darkgreen', 'darkorange', 'hotpink', 'lightgreen', 'cyan', 'yellow', 'magenta', 'chocolate',
73 'navy', 'slategray', 'olive' ]
74
75figsize = (12, 8)
76figsize_one = (10, 6)
77figsize_coeff = (8, 6)
78fontsize = 12
79legend_fontsize = 8
80legend_fontsize_one = 12
81
82
83#=============================
84# Treat argments
85#=============================
86def usage(app = None, cparams = None):
87 """
88 コマンドライン引数の使い方を表示する。
89
90 詳細説明:
91 アプリケーションとパラメータオブジェクトから利用方法文字列を取得し、整形して標準出力に出力する。
92
93 :param app: tkApplicationのインスタンス。
94 :param cparams: 設定パラメータを保持するオブジェクト。
95 :returns: なし
96 """
97 cparams = app.get_params()
98# app.usage(infile = cparams.infile)
99 for s in app.usage_str.split('\n'):
100 cmd = 'print({})'.format(s.rstrip())
101 eval(cmd)
102
103def initialize(app = None, cparams = None):
104 """
105 アプリケーションのパラメータを初期値で設定する。
106
107 詳細説明:
108 デバッグフラグ、プラグインディレクトリ、モード、入力ファイルパス、CIFファイルパス、X線波長、
109 2θ範囲、FWHM、ガウス比率、Yスケール、背景次数、LASSOのalphaなどの初期値を設定する。
110
111 :param app: tkApplicationのインスタンス。
112 :param cparams: 設定パラメータを保持するオブジェクト。
113 :returns: なし
114 """
115 cparams.debug = 0
116 cparams.findvalidstructure = True
117
118 cparams.plugin_dir = 'filter'
119
120 cparams.mode = 'plot'
121
122 cparams.infile = '*.txt'
123 cparams.cif_files = 'data/*.*'
124
125 cparams.beam = 'X-ray'
126 cparams.wavelength = "CuKa"
127 cparams.xmin = 20.0
128 cparams.xmax = 120.0
129 cparams.xstep = 0.02
130 cparams.fwhm = 0.2
131 cparams.Gfraction = 0.5
132
133 cparams.fwhm_smear = 0.0
134 cparams.Gfraction_smear = 0.0
135
136 cparams.yscale = 'linear'
137 cparams.BGorder = 3
138 cparams.alpha = 0.1
139
140def update_vars(app = None, cparams = None):
141 """
142 コマンドライン引数に基づいて設定パラメータを更新する。
143
144 詳細説明:
145 `sys.argv` から引数を取得し、`cparams` オブジェクトの対応する属性に設定する。
146 数値型引数は適切な型に変換される。
147
148 :param app: tkApplicationのインスタンス。
149 :param cparams: 設定パラメータを保持するオブジェクト。
150 :returns: なし
151 """
152# if getarg(2, None) is None:
153# app.terminate(usage = usage)
154
155 cparams.mode = getarg(1, cparams.mode)
156 cparams.plugin_dir = getarg(2, cparams.plugin_dir)
157 cparams.infile = getarg(3, cparams.infile)
158 cparams.cif_files = getarg(4, cparams.cif_files)
159 cparams.wavelength = getarg(5, cparams.wavelength)
160 cparams.xmin = getfloatarg(6, cparams.xmin)
161 cparams.xmax = getfloatarg(7, cparams.xmax)
162 cparams.xstep = getfloatarg(8, cparams.xstep)
163 cparams.fwhm = getfloatarg(9, cparams.fwhm)
164 cparams.Gfraction = getfloatarg(10, cparams.Gfraction)
165 cparams.fwhm_smear = getfloatarg(11, cparams.fwhm_smear)
166 cparams.Gfraction_smear = getfloatarg(12, cparams.Gfraction_smear)
167 cparams.yscale = getarg (13, cparams.yscale)
168 cparams.BGorder = getintarg (14, cparams.BGorder)
169 cparams.alpha = getfloatarg(15, cparams.alpha)
170
171def read_file(path, app, cparams):
172 """
173 指定されたパスのファイルを読み込み、その内容を処理する。
174
175 詳細説明:
176 登録されているモジュールを順に試行し、ファイルのタイプを判別する。
177 ファイルタイプが一致したモジュールを使用してデータを読み込み、必要に応じて変換する。
178
179 :param path: str. 読み込むファイルのパス。
180 :param app: tkApplicationのインスタンス。
181 :param cparams: 設定パラメータを保持するオブジェクト。
182 :returns: tuple. (`module`, `inf`). `module` はファイルを読み込んだモジュールオブジェクト、
183 `inf` は読み込まれたデータを含む辞書。ファイルが読み込めない場合は `(None, None)`.
184 """
185 module = None
186 for i in range(len(modules)):
187 name = module_names[i]
188 m = modules[i]
189
190 file_type = m.check_file_type(path, app = app, cparams = cparams)
191# file_type = app.call(m, "check_file_type", path, app = app, cparams = cparams)
192 print(f"try [{name}] for [{path}]: file_type={file_type}")
193 if file_type is not None and 'Error' not in file_type:
194 print(" type matched.")
195 module = m
196 break
197
198 if module is None:
199 return None, None
200
201# inf = app.call(module, "read_data", path, app = app, cparams = cparams)
202 inf = module.read_data(path, app = app, cparams = cparams)
203
204 return module, inf
205
206def read_all_files(app, cparams, input_only = False):
207 """
208 入力XRDファイルとすべてのCIFファイルを読み込む。
209
210 詳細説明:
211 `cparams.infile` で指定された入力XRDファイルを読み込み、その2θ範囲に基づいて解析範囲を調整する。
212 `cparams.cif_files` で指定されたマスクに一致するCIFファイルをすべて読み込み、変換処理を行う。
213 `input_only` が`True`の場合、入力ファイルのみを読み込む。
214
215 :param app: tkApplicationのインスタンス。
216 :param cparams: 設定パラメータを保持するオブジェクト。
217 :param input_only: bool. Trueの場合、入力ファイルのみを読み込む。
218 :returns: dict. 読み込まれたモジュールとデータを含む辞書。
219 キーは "module_input", "module_cif", "inf_input", "inf_cif_list"。
220 """
221 print("")
222 print(f"read_all_files(): Read input file [{cparams.infile}]")
223 module_input, inf_input = read_file(cparams.infile, app, cparams)
224 if module_input:
225# module_input.print_data(inf_input)
226 inf_input = module_input.convert(inf_input, cparams = cparams)
227# save_data([cparams.outfile], inf_input, cparams = cparams)
228# app.call(module_input, "plot_data", inf_input, cparams = cparams)
229 else:
230 app.terminate(f"Error in read_all_files(): Could not read [{cparams.infile}]", pause = True)
231
232 xQ2_infile = inf_input["data_list"][0]
233 xmin = min(xQ2_infile)
234 xmax = max(xQ2_infile)
235 xstep = xQ2_infile[1] - xQ2_infile[0]
236 print(f" 2Theta range: {xmin} - {xmax}, {xstep} step")
237 print(f" fwhm: {cparams.fwhm}")
238 print(f" Gaussian fraction: {cparams.Gfraction}")
239
240 cparams.xmin = max([cparams.xmin, xmin])
241 cparams.xmax = min([cparams.xmax, xmax])
242 cparams.xstep = xstep
243 print(f"2Theta range to be calculated: {cparams.xmin} - {cparams.xmax} degrees, {cparams.xstep} step")
244
245 if input_only:
246 inf = {
247 "module_input": module_input,
248 "inf_input" : inf_input,
249 }
250 return inf
251
252 cif_mask = cparams.cif_files
253 files = glob.glob(cif_mask)
254 print("")
255 print(f"Read cif and xlsx files from [{cif_mask}]")
256 inf_cif_list = []
257 module_cif = None
258 for f in files:
259 print("")
260 print(f" Read [{f}]")
261 dirname, basename, filebody, ext = split_file_path(f)
262 if len(filebody) == 0 or filebody[0] == '~':
263 print(f" [{basename}] has '~' at the first character. may be a temprary file. skip")
264 continue
265 if '-out.' in basename.lower():
266 print(f" [{basename}] include '-out.'. maybe an output file of some program. skip")
267 continue
268
269 module_cif, inf_cif = read_file(f, app, cparams)
270 if module_cif:
271 print(f" File [{f}] is red by [{module_cif.name}] module")
272# app.call(module_cif, "print_data", inf_cif)
273 inf = app.call(module_cif, "convert", inf_cif, app = app, cparams = cparams)
274# app.call(module_cif, "plot_data", inf_cif, cparams = cparams)
275
276 inf_cif_list.append(inf_cif)
277
278 inf = {
279 "module_input": module_input,
280 "module_cif" : module_cif,
281 "inf_input" : inf_input,
282 "inf_cif_list": inf_cif_list,
283 }
284
285 return inf
286
287def max_none(x):
288 """
289 None値を含むリストまたはイテラブルの最大値を返す。
290
291 詳細説明:
292 入力されたリスト `x` の要素からNoneを除外し、残りの数値の最大値を計算する。
293 数値要素が一つもない場合は、非常に小さい負の値を返す。
294
295 :param x: list or iterable. 数値とNoneを含むリストまたはイテラブル。
296 :returns: float. 最大値。
297 """
298 m = -1.0e100
299 for v in x:
300 if v is not None and m < v:
301 m = v
302 return m
303
304def min_none(x):
305 """
306 None値を含むリストまたはイテラブルの最小値を返す。
307
308 詳細説明:
309 入力されたリスト `x` の要素からNoneを除外し、残りの数値の最小値を計算する。
310 数値要素が一つもない場合は、非常に大きい正の値を返す。
311
312 :param x: list or iterable. 数値とNoneを含むリストまたはイテラブル。
313 :returns: float. 最小値。
314 """
315 m = 1.0e100
316 for v in x:
317 if v is not None and m > v:
318 m = v
319 return m
320
321def normalize_none(l, Amin = 0.0, Amax = 1.0, vmin = None, vmax = None):
322 """
323 None値を含むリストの要素を指定された範囲に正規化する。
324
325 詳細説明:
326 リスト `l` の数値要素を `[vmin, vmax]` の範囲から `[Amin, Amax]` の範囲に線形変換して正規化する。
327 `vmin` または `vmax` が指定されない場合は、リスト内のNone以外の要素から自動的に計算される。
328 None値は変更されない。
329
330 :param l: list. 数値とNoneを含むリスト。
331 :param Amin: float. 正規化後の最小値。デフォルトは 0.0。
332 :param Amax: float. 正規化後の最大値。デフォルトは 1.0。
333 :param vmin: float, optional. 元データの最小値。指定しない場合は自動計算。
334 :param vmax: float, optional. 元データの最大値。指定しない場合は自動計算。
335 :returns: list. 正規化されたリスト。
336 """
337 if vmax is None:
338 vmax = max_none(l)
339 if vmin is None:
340 vmin = min_none(l)
341 if vmax - vmin == 0.0:
342 vmax = vmin + 1.0
343
344 for i in range(len(l)):
345 if l[i] is None:
346 continue
347
348 l[i] = (l[i] - vmin) / (vmax - vmin) * (Amax - Amin) + Amin
349
350 return l
351
352def normalize(l, Amin = 0.0, Amax = 1.0, vmin = None, vmax = None):
353 """
354 数値リストの要素を指定された範囲に正規化する。
355
356 詳細説明:
357 リスト `l` の要素を `[vmin, vmax]` の範囲から `[Amin, Amax]` の範囲に線形変換して正規化する。
358 `vmin` または `vmax` が指定されない場合は、リスト内の要素から自動的に計算される。
359 入力リストがNoneの場合はNoneを返す。
360
361 :param l: list. 数値のリスト。
362 :param Amin: float. 正規化後の最小値。デフォルトは 0.0。
363 :param Amax: float. 正規化後の最大値。デフォルトは 1.0。
364 :param vmin: float, optional. 元データの最小値。指定しない場合は自動計算。
365 :param vmax: float, optional. 元データの最大値。指定しない場合は自動計算。
366 :returns: list or None. 正規化されたリスト、または入力がNoneの場合はNone。
367 """
368 if l is None:
369 return None
370
371 if vmax is None:
372 vmax = max(l)
373 if vmin is None:
374 vmin = min(l)
375 if vmax - vmin == 0.0:
376 vmax = vmin + 1.0
377
378 for i in range(len(l)):
379 l[i] = (l[i] - vmin) / (vmax - vmin) * (Amax - Amin) + Amin
380
381 return l
382
383def plot_all(inf, app, cparams):
384 """
385 実験XRDパターンとCIFからの理論パターンを個別のサブプロットに表示する。
386
387 詳細説明:
388 入力された実験XRDパターンを最上段のサブプロットに表示し、
389 その後、読み込まれた各CIFファイルから計算されたXRDパターンをそれぞれ異なるサブプロットに表示する。
390 各理論パターンには回折ピーク位置もプロットされる。すべてのプロットは共通の2θ軸を共有する。
391
392 :param inf: dict. 読み込まれたデータを含む辞書。
393 :param app: tkApplicationのインスタンス。
394 :param cparams: 設定パラメータを保持するオブジェクト。
395 :returns: なし
396 """
397 print("")
398 print("#########################################")
399 print(" Plot one XRD curve in a different box")
400 print("#########################################")
401 module_input = inf["module_input"]
402 module_cif = inf["module_cif"]
403 inf_input = inf["inf_input"]
404 inf_cif_list = inf["inf_cif_list"]
405
406 if module_cif is None:
407 app.terminate(f"Error in plot_all(): CIFファイルが見つかりませんでした", pause = True)
408
409 ncif = len(inf_cif_list)
410 print("")
411 print("plot")
412 print(f"yscale: {cparams.yscale}")
413 print("# of cif data:", ncif)
414
415 sample_infile = inf_input["sample_name"]
416 xQ2_infile = inf_input["data_list"][0]
417 yobs_infile = inf_input["data_list"][1]
418 if len(inf_input["data_list"]) >= 3:
419 ysim_infile = inf_input["data_list"][2]
420 else:
421 ysim_infile = None
422
423 vmax = max(yobs_infile)
424 vmin = min(yobs_infile)
425 yobs_infile = normalize(yobs_infile, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
426 if ysim_infile is not None:
427 ysim_infile = normalize(ysim_infile, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
428
429 fig, axes = plt.subplots(ncif + 1, 1, figsize = figsize, sharex=True, gridspec_kw={'hspace': 0})
430 plot_event = tkPlotEvent(plt, distance = 'x')
431 ncolors = len(colors)
432 nmarkers = len(markers)
433
434 ax0 = axes[0]
435 ax0.tick_params(labelsize = fontsize)
436 ax0.set_yticks([])
437 ax0.set_xlabel(None)
438 ax_bottom = axes[ncif]
439
440 for i in range(1, ncif + 1):
441 ax = axes[i]
442 ax.tick_params(labelsize = fontsize)
443 if i < ncif:
444# ax.set_xticks([])
445 ax.set_xlabel(None)
446 ax.set_yticks([])
447
448 ax = axes[0]
449 ax.set_title(f"{sample_infile}")
450 ax.tick_params(labelsize = fontsize)
451 ax.plot(xQ2_infile, yobs_infile, label = "obs", color = colors[0], linewidth = 0.5)
452 if ysim_infile is not None:
453 ax.plot(xQ2_infile, ysim_infile, label = "sim", color = colors[1], linewidth = 0.3)
454 ax.axhline(0.0, linestyle = 'dashed', color = 'red', linewidth = 0.5)
455 if cparams.yscale == 'log':
456 ax.set_yscale('log')
457 if ysim_infile is None:
458 ymax = max(yobs_infile)
459 else:
460 ymax = max([max(ysim_infile), max(yobs_infile)])
461 ax.set_ylim([1.0e-4 * ymax, ax.get_ylim()[1]])
462 ax.legend(fontsize = legend_fontsize)
463
464 for i in range(1, ncif + 1):
465 inf_cif = inf_cif_list[i - 1]
466 xQ2, xrd_cal = inf_cif["conv_data"]
467 filename = inf_cif["filename"]
468 dirname, basename, filebody, ext = split_file_path(filename)
469
470 src = inf_cif["diffractions"]["source"]
471 Q2 = inf_cif["diffractions"]["Q2"]
472 dhkl = inf_cif["diffractions"]["dhkl"]
473 hkl = inf_cif["diffractions"]["hkl"]
474 mul = inf_cif["diffractions"].get("mul", None)
475 if mul is None:
476 mul = [0 for i in range(len(src))]
477 Int = inf_cif["diffractions"]["intensity"]
478 ndiffractions = len(Q2)
479
480 vmax = max(xrd_cal)
481 vmin = min(xrd_cal)
482 xrd_cal = normalize(xrd_cal, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
483 Int = normalize(Int, Amin = 0.0, Amax = 1.0)
484
485 ax = axes[i]
486 color = colors[(i - 1) % ncolors]
487 marker = markers[(i - 1) % nmarkers]
488 phase = [filebody] * ndiffractions
489
490 ax.plot(xQ2, xrd_cal, label = filebody, color = 'black', linewidth = 0.5)
491 data = ax.plot(Q2, Int, linestyle = '', marker = marker, markerfacecolor = color, markeredgecolor = color, markersize = 2.0)
492 data0 = ax0.plot(Q2, Int, linestyle = '', marker = marker, markerfacecolor = color, markeredgecolor = color, markersize = 2.0)
493 for j in range(ndiffractions):
494# data0 = ax0.plot([Q2[j], Q2[j]], [0.0, Int[j]], linestyle = 'dashed', color = color, linewidth = 0.5)
495 ax.plot([Q2[j], Q2[j]], [0.0, Int[j]], linestyle = 'dashed', color = color, linewidth = 0.5)
496 ax0.plot([Q2[j], Q2[j]], [0.0, Int[j]], linestyle = 'dashed', color = color, linewidth = 0.5)
497
498#plot_event.add_data({"label": "diffraction", "plot_type": "2D", "axis": ax, "data": [Q2, dhkl, hkl, mul, Int]})
499 hkl_str = [f"{hkl[i][0]} {hkl[i][1]} {hkl[i][2]}" for i in range(ndiffractions)]
500 plot_event.add_data({"label": "diffraction", "plot_type": "2D", "axis": ax, "data": data,
501 "x": Q2, 'y': Int, "xlabel": "2Theta", "ylabel": "Intensity",
502 "xlist": [src, phase, Q2, dhkl, hkl_str, mul, Int],
503 "xlabels": ['X-ray', 'phase', 'Q2', 'dhkl', 'hkl', 'multiplicity', 'Intensity']
504 })
505 plot_event.add_data({"label": "diffraction", "plot_type": "2D", "axis": ax0, "data": data0,
506 "x": Q2, 'y': Int, "xlabel": "2Theta", "ylabel": "Intensity",
507 "xlist": [src, phase, Q2, dhkl, hkl_str, mul, Int],
508 "xlabels": ['X-ray', 'phase', 'Q2', 'dhkl', 'hkl', 'multiplicity', 'Intensity']
509 })
510
511 ax.axhline(0.0, linestyle = 'dashed', color = 'red', linewidth = 0.5)
512 if cparams.yscale == 'log':
513 ax.set_yscale('log')
514 ymax = max(xrd_cal)
515 ax.set_ylim([1.0e-4 * ymax, ax.get_ylim()[1]])
516 ax.legend(fontsize = legend_fontsize)
517
518 xmin = max([inf_input["xmin"], cparams.xmin])
519 xmax = min([inf_input["xmax"], cparams.xmax])
520
521 for ax in axes:
522 for q2 in range(int(xmin), int(xmax)):
523 if q2 % 5 == 0:
524 ax.axvline(q2, linestyle = 'dotted', linewidth = 0.5, color = 'black')
525 else:
526 ax.axvline(q2, linestyle = 'dotted', linewidth = 0.3, color = 'gray')
527
528 ax.set_xlim(xmin, xmax)
529
530 plot_event.register_click(fig) #callback = lambda event: plot_event.onclick(event))
531# plot_event.register_event(fig, event = "button_press_event",
532# callback = lambda event: plot_event.onclick(event))
533
534 ax_bottom.set_xlabel(r'2$\theta$', fontsize = fontsize)
535 axes[int(ncif/2)].set_ylabel('Intensity', fontsize = fontsize)
536 ax.legend(fontsize = legend_fontsize)
537
538 plt.tight_layout()
539 plt.pause(0.1)
540
541 input("Press ENTER to terminate>>")
542
543def plot_input(inf, app, cparams):
544 """
545 入力された実験XRDパターンのみをプロットする。
546
547 詳細説明:
548 `inf` から実験XRDデータを取得し、一つのグラフにプロットする。
549 Y軸のスケールは `cparams.yscale` に従う。
550
551 :param inf: dict. 読み込まれたデータを含む辞書。
552 :param app: tkApplicationのインスタンス。
553 :param cparams: 設定パラメータを保持するオブジェクト。
554 :returns: なし
555 """
556 print("")
557 print("#########################################")
558 print(" Plot input XRD curve")
559 print("#########################################")
560 module_input = inf["module_input"]
561 inf_input = inf["inf_input"]
562
563 print("")
564 print("plot")
565 print(f"yscale: {cparams.yscale}")
566
567 sample_infile = inf_input["sample_name"]
568 xQ2_infile = inf_input["data_list"][0]
569 yobs_infile = inf_input["data_list"][1]
570
571 fig = plt.figure(figsize = figsize_one)
572 ax = fig.add_subplot(1, 1, 1)
573 ax.tick_params(labelsize = fontsize)
574
575 ax.set_title(f"{sample_infile}")
576 ax.plot(xQ2_infile, yobs_infile, label = "obs", color = colors[0], linewidth = 0.5)
577# ax.legend(fontsize = legend_fontsize)
578
579 Qmin = max([inf_input["xmin"], cparams.xmin])
580 Qmax = min([inf_input["xmax"], cparams.xmax])
581 ax.set_xlim(Qmin, Qmax)
582 ax.set_xlabel('2$\\theta$ ($\\degree$)', fontsize = fontsize)
583 ax.set_ylabel('Intensity', fontsize = fontsize)
584 if cparams.yscale == 'log':
585 ax.set_yscale('log')
586# ymax = max(yobs_infile)
587# ax.set_ylim([1.0e-4 * ymax, ax.get_ylim()[1]])
588
589 plt.tight_layout()
590 plt.pause(0.1)
591
592 input("Press ENTER to terminate>>")
593
594def plot_one(inf, app, cparams):
595 """
596 実験XRDパターンとCIFからの回折ピーク位置を同じグラフに表示する。
597
598 詳細説明:
599 入力された実験XRDパターンと、読み込まれた各CIFファイルから計算された回折ピーク位置(強度は正規化)を
600 同一のグラフにプロットする。これにより、実験パターンと各結晶相のピーク位置の関係を一度に確認できる。
601
602 :param inf: dict. 読み込まれたデータを含む辞書。
603 :param app: tkApplicationのインスタンス。
604 :param cparams: 設定パラメータを保持するオブジェクト。
605 :returns: なし
606 """
607 print("")
608 print("#########################################")
609 print(" Plot input XRD curve and cif diffraction angles in one graph")
610 print("#########################################")
611 module_input = inf["module_input"]
612 module_cif = inf["module_cif"]
613 inf_input = inf["inf_input"]
614 inf_cif_list = inf["inf_cif_list"]
615
616 if module_cif is None:
617 app.terminate(f"Error in plot_all(): CIFファイルが見つかりませんでした", pause = True)
618
619 ncif = len(inf_cif_list)
620 print("")
621 print("plot")
622 print(f"yscale: {cparams.yscale}")
623 print("# of cif data:", ncif)
624
625 sample_infile = inf_input["sample_name"]
626 xQ2_infile = inf_input["data_list"][0]
627 yobs_infile = inf_input["data_list"][1]
628 if len(inf_input["data_list"]) >= 3:
629 ysim_infile = inf_input["data_list"][2]
630 else:
631 ysim_infile = None
632
633 vmax = max(yobs_infile)
634 vmin = min(yobs_infile)
635 yobs_infile = normalize(yobs_infile, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
636 if ysim_infile is not None:
637 ysim_infile = normalize(ysim_infile, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
638
639 fig = plt.figure(figsize = figsize_one)
640 plot_event = tkPlotEvent(plt, distance = 'x')
641 ncolors = len(colors)
642 nmarkers = len(markers)
643
644 ax = fig.add_subplot(1, 1, 1)
645# ax.set_xticks([])
646 ax.set_yticks([])
647 ax.set_xlabel(None)
648 ax.set_title(f"{sample_infile}")
649 ax.tick_params(labelsize = fontsize)
650 ax.plot(xQ2_infile, yobs_infile, label = "obs", color = colors[0], linewidth = 0.5)
651 if ysim_infile is not None:
652 ax.plot(xQ2_infile, ysim_infile, label = "sim", color = colors[1], linewidth = 0.3)
653 ax.legend(fontsize = legend_fontsize)
654
655 if ysim_infile is None:
656 ymax = max(yobs_infile)
657 else:
658 ymax = max([max(yobs_infile), max(ysim_infile)])
659 for i in range(1, ncif + 1):
660 inf_cif = inf_cif_list[i - 1]
661 xQ2, xrd_cal = inf_cif["conv_data"]
662 filename = inf_cif["filename"]
663 dirname, basename, filebody, ext = split_file_path(filename)
664
665 src = inf_cif["diffractions"]["source"]
666 Q2 = inf_cif["diffractions"]["Q2"]
667 dhkl = inf_cif["diffractions"]["dhkl"]
668 hkl = inf_cif["diffractions"]["hkl"]
669 mul = inf_cif["diffractions"].get("mul", None)
670 if mul is None:
671 mul = [0 for i in range(len(src))]
672 Int = inf_cif["diffractions"]["intensity"]
673 ndiffractions = len(Q2)
674
675 vmax = max(xrd_cal)
676 vmin = min(xrd_cal)
677 xrd_cal = normalize(xrd_cal, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
678 Int = normalize(Int, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
679
680 color = colors[(i - 1) % ncolors]
681 marker = markers[(i - 1) % nmarkers]
682 phase = [filebody] * ndiffractions
683
684 data0 = ax.plot(Q2, Int, linestyle = '', marker = marker, markerfacecolor = color, markeredgecolor = color, markersize = 2.0)
685 ymax = max([max(Int), ymax])
686 for j in range(ndiffractions):
687# data0 = ax.plot([Q2[j], Q2[j]], [0.0, Int[j]], linestyle = 'dashed', color = color, linewidth = 0.5)
688 ax.plot([Q2[j], Q2[j]], [0.0, Int[j]], linestyle = 'dashed', color = color, linewidth = 0.5)
689
690 if len(hkl[0]) == 3:
691 hkl_str = [f"{hkl[i][0]} {hkl[i][1]} {hkl[i][2]}" for i in range(ndiffractions)]
692 else:
693 hkl_str = [f"{hkl[i][0]} {hkl[i][1]} ({hkl[i][2]}) {hkl[i][3]}" for i in range(ndiffractions)]
694 plot_event.add_data({"label": "diffraction", "plot_type": "2D", "axis": ax, "data": data0,
695 "x": Q2, 'y': Int, "xlabel": "2Theta", "ylabel": "Intensity",
696 "xlist": [src, phase, Q2, dhkl, hkl_str, mul, Int],
697 "xlabels": ["X-ray", 'phase', 'Q2', 'dhkl', 'hkl', 'multiplicity', 'Intensity']
698 })
699
700 ymax = max([max(Int), ymax])
701 ax.legend(fontsize = legend_fontsize)
702
703 plot_event.register_click(fig) #callback = lambda event: plot_event.onclick(event))
704# plot_event.register_event(fig, event = "button_press_event",
705# callback = lambda event: plot_event.onclick(event))
706
707 Qmin = max([inf_input["xmin"], cparams.xmin])
708 Qmax = min([inf_input["xmax"], cparams.xmax])
709 ax.set_xlim(Qmin, Qmax)
710 ax.set_ylabel('Intensity', fontsize = fontsize)
711 if cparams.yscale == 'log':
712 ax.set_yscale('log')
713 ax.set_ylim([1.0e-4 * ymax, ax.get_ylim()[1]])
714
715 plt.tight_layout()
716 plt.pause(0.1)
717
718 input("Press ENTER to terminate>>")
719
720def plot_one2(inf, app, cparams):
721 """
722 実験XRDパターンとCIFからの理論XRDパターンを同じグラフに表示する。
723
724 詳細説明:
725 入力された実験XRDパターンと、読み込まれた各CIFファイルから計算された理論XRDパターン(ブロードニング適用済み)を
726 同一のグラフにプロットする。これにより、実験パターンと各結晶相の回折プロファイルの形状を一度に比較できる。
727
728 :param inf: dict. 読み込まれたデータを含む辞書。
729 :param app: tkApplicationのインスタンス。
730 :param cparams: 設定パラメータを保持するオブジェクト。
731 :returns: なし
732 """
733 print("")
734 print("#########################################")
735 print(" Plot XRD curves in one graph")
736 print("#########################################")
737 module_input = inf["module_input"]
738 module_cif = inf["module_cif"]
739 inf_input = inf["inf_input"]
740 inf_cif_list = inf["inf_cif_list"]
741
742 if module_cif is None:
743 app.terminate(f"Error in plot_all(): CIFファイルが見つかりませんでした", pause = True)
744
745 ncif = len(inf_cif_list)
746 print("")
747 print("plot")
748 print(f"yscale: {cparams.yscale}")
749 print("# of cif data:", ncif)
750
751 sample_infile = inf_input["sample_name"]
752 xQ2_infile = inf_input["data_list"][0]
753 yobs_infile = inf_input["data_list"][1]
754 if len(inf_input["data_list"]) >= 3:
755 ysim_infile = inf_input["data_list"][2]
756 else:
757 ysim_infile = None
758
759 vmax = max(yobs_infile)
760 vmin = min(yobs_infile)
761 yobs_infile = normalize(yobs_infile, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
762 if ysim_infile is not None:
763 ysim_infile = normalize(inf_input["data_list"][2], Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
764
765 fig = plt.figure(figsize = figsize_one)
766 plot_event = tkPlotEvent(plt, distance = 'x')
767 ncolors = len(colors)
768 nmarkers = len(markers)
769
770 ax = fig.add_subplot(1, 1, 1)
771# ax.set_xticks([])
772 ax.set_yticks([])
773 ax.set_xlabel(None)
774 ax.set_title(f"{sample_infile}")
775 ax.tick_params(labelsize = fontsize)
776 ax.plot(xQ2_infile, yobs_infile, label = "obs", color = colors[0], linewidth = 1.0)
777# ax.plot(xQ2_infile, ysim_infile, label = "sim", color = colors[1], linewidth = 0.3)
778
779 ymax = max(yobs_infile)
780 for i in range(1, ncif + 1):
781 inf_cif = inf_cif_list[i - 1]
782 xQ2, xrd_cal = inf_cif["conv_data"]
783 filename = inf_cif["filename"]
784 dirname, basename, filebody, ext = split_file_path(filename)
785
786 vmax = max(xrd_cal)
787 vmin = min(xrd_cal)
788 xrd_cal = normalize(xrd_cal, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
789
790 ax.plot(xQ2, xrd_cal, label = filebody, linestyle = '-', color = colors[i % ncolors], linewidth = 0.5)
791 ymax = max([ymax, max(xrd_cal)])
792
793 Qmin = max([inf_input["xmin"], cparams.xmin])
794 Qmax = min([inf_input["xmax"], cparams.xmax])
795 ax.set_xlim(Qmin, Qmax)
796 ax.set_ylabel('Intensity', fontsize = fontsize)
797 if cparams.yscale == 'log':
798 ax.set_yscale('log')
799 ax.set_ylim([1.0e-4 * ymax, ax.get_ylim()[1]])
800 ax.legend(fontsize = legend_fontsize)
801
802 plt.tight_layout()
803 plt.pause(0.1)
804
805 input("Press ENTER to terminate>>")
806
807def convolution(x, y, filter, nskip = 1):
808 """
809 データ `y` を指定された `filter` で畳み込む。
810
811 詳細説明:
812 離散的な畳み込み演算を実行し、`y` の各点において `filter` を適用して
813 平滑化された(またはブロードニングされた)データ `yc` を生成する。
814 `nskip` パラメータで畳み込みの計算間隔を制御し、結果のデータ点数を減らすことができる。
815
816 :param x: list or array. x座標のリスト。
817 :param y: list or array. 畳み込み対象のy座標のリスト。
818 :param filter: list or array. 畳み込みに使用するフィルタの配列。
819 :param nskip: int. 畳み込み計算をスキップする間隔。1の場合、すべての点で計算する。
820 :returns: tuple. (`_x`, `_y`). 畳み込み後のx座標とy座標のリスト。`y` がNoneの場合はNoneを返す。
821 """
822 if y is None:
823 return None
824
825 ny = len(y)
826 nconv = len(filter) // 2
827 yc = np.zeros(ny)
828 for i in range(0, ny, nskip):
829 for idf in range(-nconv, nconv + 1):
830 i1 = i + idf
831 if i1 % nskip == 0 and 0 <= i1 < ny:
832 yc[i] += filter[idf] * y[i1]
833
834 _x = [x[i] for i in range(0, ny, nskip)]
835 _y = [yc[i] for i in range(0, ny, nskip)]
836
837 return _x, _y
838# return x, yc
839
840def collect_data(inf, app, cparams, is_print = True):
841 """
842 フィッティングや相関分析のために、実験および理論XRDデータを収集・前処理する。
843
844 詳細説明:
845 入力された実験XRDデータと各CIFファイルから計算された理論XRDデータを統一された2θ範囲に補間し、
846 スマアリング(畳み込み)と正規化を適用する。さらに、背景多項式のための基底関数も準備する。
847
848 :param inf: dict. 読み込まれたデータを含む辞書。
849 :param app: tkApplicationのインスタンス。
850 :param cparams: 設定パラメータを保持するオブジェクト。
851 :param is_print: bool. 処理の詳細をコンソールに出力するかどうか。
852 :returns: tuple. (Q2_list, yobs_infile, ysim_infile, bg_names, bg_list, sample_names, ycif_list, labels_train, x_train)。
853 - `Q2_list`: list. 共通の2θ座標のリスト。
854 - `yobs_infile`: list. 前処理された実験XRD強度データ。
855 - `ysim_infile`: list or None. 前処理されたシミュレーションXRD強度データ(存在する場合)。
856 - `bg_names`: list. 背景多項式のラベルのリスト。
857 - `bg_list`: list. 背景多項式の基底関数(レジェンドル多項式)のリスト。
858 - `sample_names`: list. CIFファイルから取得した試料名またはファイルボディ名のリスト。
859 - `ycif_list`: list. 各CIFファイルから計算され前処理された理論XRD強度データのリスト。
860 - `labels_train`: list. 学習データ(x_train)の各列に対応するラベルのリスト。
861 - `x_train`: list. 学習データとなる背景多項式と理論XRD強度のリスト。
862 """
863 module_input = inf["module_input"]
864 inf_input = inf["inf_input"]
865 inf_cif_list = inf["inf_cif_list"]
866 ncif = len(inf_cif_list)
867 nspectrum = inf_input["nspectrum"]
868
869 if ncif < 1:
870 app.terminate(f"\nError: CIF file is not found.\n", pause = True)
871
872 fwhm = cparams.fwhm_smear
873 Gf = cparams.Gfraction_smear
874 dQ2 = 12.0 * fwhm
875 nconv = int(dQ2 / cparams.xstep + 1.00001)
876 filter = [0.0] * (2 * nconv + 1)
877 if fwhm <= 0.0:
878 wGL = 1.0
879 else:
880 wGL = GaussLorentz(0.0, 0.0, fwhm / 2.0, C0 = 1.0, Gfraction = Gf, Gwratio = 1.0, A = None)
881 for i in range(-nconv, nconv + 1):
882 if fwhm <= 0.0:
883 filter[i] = 0.0
884 else:
885 filter[i] = GaussLorentz(0.0, i * cparams.xstep, fwhm / 2.0, C0 = 1.0, Gfraction = Gf, Gwratio = 1.0, A = None) / wGL
886
887 sample_infile = inf_input["sample_name"]
888 xQ2_infile = inf_input["data_list"][0]
889 nx_in = len(xQ2_infile)
890 dx = xQ2_infile[1] - xQ2_infile[0]
891 nskip = int(fwhm / dx / 5.0 + 1.0e-5)
892 if nskip == 0:
893 nskip = 1
894 minnx = 500
895 if int(nx_in / nskip) < minnx:
896 nskip = int(nx_in / minnx)
897# nskip = 1
898
899 yobs_infile = inf_input["data_list"][1]
900 if nspectrum >= 3:
901 ysim_infile = inf_input["data_list"][2]
902 else:
903 ysim_infile = None
904
905 if cparams.yscale == 'log':
906 yobs_infile = log(yobs_infile)
907 if ysim_infile is not None:
908 ysim_infile = log(ysim_infile)
909 if fwhm > 0.0:
910 _xQ2_infile, yobs_infile = convolution(xQ2_infile, yobs_infile, filter, nskip = nskip)
911 if ysim_infile is not None:
912 _xQ2_infile, ysim_infile = convolution(xQ2_infile, ysim_infile, filter, nskip = nskip)
913 else:
914 _xQ2_infile = xQ2_infile
915
916 vmax = max(yobs_infile)
917 vmin = min(yobs_infile)
918 yobs_infile = normalize(yobs_infile, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
919 if ysim_infile is not None:
920 ysim_infile = normalize(ysim_infile, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
921
922 print(f"Read CIF data from {ncif} files")
923 xQ2 = None
924 ycif_list = []
925 sample_names = []
926 for i in range(1, ncif + 1):
927 inf_cif = inf_cif_list[i - 1]
928 xQ2, xrd_cal = inf_cif["conv_data"]
929 maxy = abs(max(xrd_cal))
930 if cparams.yscale == 'log':
931 xrd_cal = log(xrd_cal + maxy * 1.0e-7)
932
933 if fwhm > 0.0:
934 _xQ2, xrd_cal = convolution(xQ2, xrd_cal, filter, nskip = nskip)
935 else:
936 _xQ2 = xQ2
937
938 xrd_cal = normalize(xrd_cal, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
939 xrd_cal = normalize(xrd_cal, Amin = 0.0, Amax = 1.0)
940
941 filename = inf_cif["filename"]
942 dirname, basename, filebody, ext = split_file_path(filename)
943
944 ycif_list.append(xrd_cal)
945 sample_names.append(filebody)
946
947 nx = len(xQ2)
948 xmin = min(xQ2)
949 xmax = max(xQ2)
950 xstep = (xmax - xmin) / (nx - 1)
951 x_list = []
952 Q2_list = []
953 for i in range(nx):
954 x_list.append(-1 + i * xstep)
955 Q2_list.append(xmin + i * xstep)
956
957 func1d = interp1d(_xQ2_infile, yobs_infile, bounds_error = False, fill_value = (0.0, 0.0))
958# func1d = interp1d(xQ2_infile, yobs_infile, bounds_error = False, fill_value = (0.0, 0.0))
959 yobs_infile = func1d(Q2_list)
960 if ysim_infile is not None:
961 func1d = interp1d(_xQ2_infile, ysim_infile, bounds_error = False, fill_value = (0.0, 0.0))
962# func1d = interp1d(xQ2_infile, ysim_infile, bounds_error = False, fill_value = (0.0, 0.0))
963 ysim_infile = func1d(Q2_list)
964 for i in range(1, ncif + 1):
965 func1d = interp1d(_xQ2, ycif_list[i-1], bounds_error = False, fill_value = (0.0, 0.0))
966# func1d = interp1d(xQ2, ycif_list[i-1], bounds_error = False, fill_value = (0.0, 0.0))
967 ycif_list[i-1] = func1d(Q2_list)
968
969 bg_list = []
970 for order in range(cparams.BGorder + 1):
971 poly1d = legendre(order)
972 bg_list.append(poly1d(x_list))
973
974 if is_print:
975 print("# of cif data:", ncif)
976 print("BG order :", cparams.BGorder)
977
978 bg_names = [f"BG_order_{i}" for i in range(cparams.BGorder + 1)] # BG_order+1個の多項式基底
979 x_train = bg_list.copy()
980 labels_train = bg_names.copy()
981 x_train.extend(ycif_list)
982 labels_train.extend(sample_names) # CIFファイルの名前を追加
983
984 return Q2_list, yobs_infile, ysim_infile, bg_names, bg_list, sample_names, ycif_list, labels_train, x_train
985
986def check_overwrap(inf, app, cparams):
987 """
988 異なるCIFファイル由来のXRDパターン間のオーバーラップ(重なり)をチェックし、可視化する。
989
990 詳細説明:
991 各CIFファイルの回折ピークが、他のCIFファイルから生成された回折パターンとどの程度重なっているかを計算し、
992 その結果をプロットする。これにより、複数の結晶相が混在する場合に、各相のピークが互いに干渉する度合いを評価できる。
993
994 :param inf: dict. 読み込まれたデータを含む辞書。
995 :param app: tkApplicationのインスタンス。
996 :param cparams: 設定パラメータを保持するオブジェクト。
997 :returns: なし
998 """
999 print("")
1000 print("#########################################")
1001 print(" Check overwrap between cif XRD patterns")
1002 print("#########################################")
1003 print(f" smearing: fwhm={cparams.fwhm_smear} Gaussian fraction={cparams.Gfraction_smear}")
1004 inf_cif_list = inf["inf_cif_list"]
1005
1006 Q2_list, yobs_infile, ysim_infile, bg_names, bg_list, sample_names, ycif_list, labels_train, x_train = collect_data(inf, app, cparams)
1007 nx = len(Q2_list)
1008 Qmin = Q2_list[0]
1009 Qmax = Q2_list[nx - 1]
1010 ncif = len(ycif_list)
1011 nxtrain = len(x_train)
1012
1013 fwhm = cparams.fwhm + cparams.fwhm_smear
1014 Gf = cparams.Gfraction_smear
1015 dQ2 = fwhm # FWHMを考慮した畳み込み幅
1016 nconv = int(dQ2 / cparams.xstep + 1.00001)
1017 filter = [0.0] * (2 * nconv + 1)
1018 if fwhm <= 0.0:
1019 wGL = 1.0
1020 else:
1021 # FWHMの半分を半値幅として使用
1022 wGL = GaussLorentz(0.0, 0.0, fwhm / 2.0, C0 = 1.0, Gfraction = Gf, Gwratio = 1.0, A = None)
1023 for i in range(-nconv, nconv + 1):
1024 if fwhm <= 0.0:
1025 filter[i] = 0.0
1026 else:
1027 filter[i] = GaussLorentz(0.0, i * cparams.xstep, fwhm / 2.0, C0 = 1.0, Gfraction = Gf, Gwratio = 1.0, A = None) / wGL
1028# print("nconv=", nconv)
1029# print("filter=", filter)
1030
1031 # 構造のピークが他の構造のブロードニングされたパターンに与える影響を計算
1032 corr = make_matrix3(ncif, ncif, nx)
1033 for ic in range(ncif):
1034 inf = inf_cif_list[ic]
1035 Q2 = inf["diffractions"]["Q2"]
1036 Int = inf["diffractions"]["intensity"]
1037 nd = len(Q2)
1038 ndiffractions = len(Q2)
1039
1040 for ic2 in range(ncif):
1041 if ic == ic2:
1042 continue
1043
1044 ycif = ycif_list[ic2] # 他のCIFパターン
1045
1046 for id in range(nd):
1047 Q20 = Q2[id] # 現在のCIFのピーク位置
1048
1049 id0 = None
1050 for i in range(nx):
1051 if Q20 <= Q2_list[i]:
1052 id0 = i
1053 break
1054
1055 if id0 is None:
1056 continue
1057
1058 # ピーク位置 Q20 を中心に、ブロードニングフィルターを適用
1059 for idf in range(-nconv, nconv + 1):
1060 i1 = id0 + idf
1061 if 0 <= i1 < nx:
1062 # 現在のピーク強度 * フィルタ値 * 他のCIFパターンの強度
1063 # これはオーバーラップの度合いを示す
1064 v = filter[idf] * Int[id] * ycif[i1]
1065 if corr[ic][ic2][i1] is None:
1066 corr[ic][ic2][i1] = v
1067 else:
1068 corr[ic][ic2][i1] += v
1069# print("corr=", corr)
1070
1071 fig, axes = plt.subplots(ncif, 1, figsize = figsize, sharex=True, gridspec_kw={'hspace': 0})
1072 plot_event = tkPlotEvent(plt, distance = 'x')
1073 ncolors = len(colors)
1074 nmarkers = len(markers)
1075
1076 for ic in range(ncif):
1077 inf = inf_cif_list[ic]
1078 src = inf["diffractions"]["source"]
1079 Q2 = inf["diffractions"]["Q2"]
1080 dhkl = inf["diffractions"]["dhkl"]
1081 hkl = inf["diffractions"]["hkl"]
1082 mul = inf["diffractions"].get("mul", None)
1083 if mul is None:
1084 mul = [0 for i in range(len(src))]
1085 Int = inf["diffractions"]["intensity"]
1086 ndiffractions = len(Q2)
1087 filename = inf["filename"]
1088 dirname, basename, filebody, ext = split_file_path(filename)
1089 phase = [filebody] * ndiffractions
1090
1091 ax = axes[ic]
1092 ax.tick_params(labelsize = fontsize)
1093 ax2 = ax.twinx()
1094 ax2.tick_params(labelsize = 0)
1095 ycif = ycif_list[ic]
1096 ax.plot([], [], label = filebody, linestyle = '') # フェーズ名を表示するためのダミープロット
1097 ax2.plot(Q2_list, ycif, picker = True, linestyle = 'dashed', color = 'black', linewidth = 0.5)
1098
1099 for ic2 in range(ncif):
1100 if ic == ic2:
1101 continue
1102
1103 inf_cif2 = inf_cif_list[ic2]
1104 filename = inf_cif2["filename"]
1105 dirname, basename, filebody, ext = split_file_path(filename)
1106
1107 color = colors[ic2 % ncolors]
1108 marker = markers[ic2 % ncolors]
1109
1110 y = corr[ic][ic2]
1111 vmax = max_none(y)
1112 vmin = min_none(y)
1113 y = normalize_none(y, Amin = 0.0, Amax = 1.0, vmin = vmin, vmax = vmax)
1114 Int = normalize(Int, Amin = 0.0, Amax = 1.0) # ピーク強度を正規化
1115
1116 ax.plot(Q2_list, y, label = filebody, picker = True, color = color, linewidth = 1.0) # オーバーラッププロット
1117
1118 data = ax.plot(Q2, Int, linestyle = '', marker = marker, markerfacecolor = color, markeredgecolor = 'black', markersize = 2.0)
1119 for j in range(ndiffractions):
1120 ax.plot([Q2[j], Q2[j]], [0.0, Int[j]], linestyle = 'dashed', color = 'black', linewidth = 0.5)
1121
1122 hkl_str = [f"{hkl[i][0]} {hkl[i][1]} {hkl[i][2]}" for i in range(ndiffractions)]
1123 plot_event.add_data({"label": "diffraction", "plot_type": "2D", "axis": ax, "data": data,
1124 "x": Q2, 'y': Int, "xlabel": "2Theta", "ylabel": "Intensity",
1125 "xlist": [src, phase, Q2, dhkl, hkl_str, mul, Int],
1126 "xlabels": ['X-ray', 'phase', 'Q2', 'dhkl', 'hkl', 'multiplicity', 'Intensity']
1127 })
1128
1129 ax.set_xlim([Qmin, Qmax])
1130 ax.legend(fontsize = legend_fontsize)
1131 if cparams.yscale == 'log':
1132 ax.set_yscale('log')
1133 ax.set_ylim([1.0e-4, ax.get_ylim()[1]])
1134 ax2.set_yscale('linear') # ax2のスケールは常にリニア
1135
1136 ax.set_xlabel(r'2$\theta$', fontsize = fontsize)
1137
1138 plot_event.register_click(fig) # callback = lambda event: plot_event.onclick(event))
1139 plot_event.register_pick(fig) # callback = lambda event: plot_event.onclick(event))
1140
1141 plt.tight_layout()
1142 plt.pause(0.1)
1143
1144 input("Press ENTER to terminate>>")
1145
1146def CIF_correlation(inf, app, cparams):
1147 """
1148 CIFファイルから生成されたXRDパターン間の相関係数を計算し、可視化する。
1149
1150 詳細説明:
1151 すべてのCIFファイルから生成された理論XRDパターン間の相関係数を計算し、結果をテキストで出力する。
1152 また、各CIFパターンと入力実験パターンとの相関係数を、スマアリングFWHMを変化させながらプロットし、
1153 最も相関の高いスマアリング条件や、異なる相間の類似性を評価する。
1154
1155 :param inf: dict. 読み込まれたデータを含む辞書。
1156 :param app: tkApplicationのインスタンス。
1157 :param cparams: 設定パラメータを保持するオブジェクト。
1158 :returns: なし
1159 """
1160 print("")
1161 print("#########################################")
1162 print(" Check correlation between cif XRD patterns")
1163 print("#########################################")
1164 print(f" smearing: fwhm={cparams.fwhm_smear} Gaussian fraction={cparams.Gfraction_smear}")
1165 inf_cif_list = inf["inf_cif_list"]
1166
1167 Q2_list, yobs_infile, ysim_infile, bg_names, bg_list, sample_names, ycif_list, labels_train, x_train = collect_data(inf, app, cparams)
1168 xlist = [yobs_infile]
1169 xlabels = ["obs"]
1170 xlist.extend(ycif_list)
1171 xlabels.extend(sample_names)
1172 nx = len(xlist)
1173 dx = Q2_list[1] - Q2_list[0]
1174
1175#相関係数
1176 print("")
1177 print("Correlation coefficients:")
1178 corr = np.zeros([nx, nx])
1179 for i in range(nx):
1180 for j in range(i, nx):
1181 corr[i][j] = np.dot(xlist[i], xlist[j])
1182 for i in range(nx):
1183 for j in range(i + 1, nx):
1184 corr[i][j] /= np.sqrt(corr[i][i] * corr[j][j])
1185 if corr[i][j] >= 0.9:
1186 print(f" identical? {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1187 elif corr[i][j] >= 0.8:
1188 print(f" similar {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1189 elif corr[i][j] >= 0.5:
1190 print(f" ***** {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1191 elif corr[i][j] >= 0.5:
1192 print(f" ***** {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1193 elif corr[i][j] >= 0.4:
1194 print(f" **** {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1195 elif corr[i][j] >= 0.3:
1196 print(f" *** {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1197 else:
1198 print(f" {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1199
1200# input dataとの相関係数をsmearing fwhmを変えながらプロット
1201 print("")
1202 print("Correlation coefficients with input data with varied smearing fwhm:")
1203 fwhm_smear_original = cparams.fwhm_smear
1204 fwhm_list = np.arange(0.0, 1.001, 0.2)
1205 corr_list = make_matrix2(nx, len(fwhm_list))
1206 for i in range(len(fwhm_list)):
1207 _fwhm = fwhm_list[i]
1208 cparams.fwhm_smear = _fwhm
1209 print(f" Calculating for fwhm={_fwhm}")
1210 Q2_list0, yobs_infile0, ysim_infile0, bg_names0, bg_list0, sample_names0, ycif_list0, labels_train0, x_train0 \
1211 = collect_data(inf, app, cparams, is_print = False)
1212
1213 nskip = int((_fwhm / 5.0) / dx + 1.0e-5)
1214# nskip = 1
1215
1216 xlist0 = [[v for i, v in enumerate(yobs_infile0) if i % nskip == 0]]
1217 for y in ycif_list0:
1218 xlist0.append([v for i, v in enumerate(y) if i % nskip == 0])
1219# xlist0 = [yobs_infile]
1220# xlist0.extend(ycif_list0)
1221 nx_sampled = len(xlist0)
1222 print(f" _fwhm={_fwhm} dx={dx} nskip={nskip} nx={len(xlist0[0])}")
1223
1224# nskip = int((_fwhm / 4.0) / dx)
1225# print("nskip = ", nskip)
1226# print("")
1227
1228 norm = make_matrix1(nx_sampled)
1229 for j in range(nx_sampled):
1230 print(f" calculating {j}-th diagonal norm")
1231 norm[j] = np.sqrt(np.dot(xlist0[j], xlist0[j]))
1232 for j in range(nx_sampled):
1233 print(f" calculating obs - {j}-th non-diagonal correlation")
1234 corr_list[j][i] = np.dot(xlist0[0], xlist0[j]) / norm[0] / norm[j]
1235
1236 cparams.fwhm_smear = fwhm_smear_original
1237
1238 print("")
1239 print("plot")
1240
1241 fig, ax = plt.subplots(1, 1, figsize = figsize_one)
1242 plot_event = tkPlotEvent(plt, distance = 'x')
1243 ncolors = len(colors)
1244
1245 for i in range(1, nx): # "obs"を除いたCIFパターンとobsの相関をプロット
1246 ax.tick_params(labelsize = fontsize)
1247 ax.plot(fwhm_list, corr_list[i], label = xlabels[i], picker = True, color = colors[i % ncolors], linewidth = 1.0)
1248
1249 ax.legend(fontsize = legend_fontsize)
1250 ax.set_xlabel(r'fwhm ($\degree$)', fontsize = fontsize)
1251 ax.set_ylabel(r'Correlation coefficient', fontsize = fontsize)
1252
1253 plot_event.register_pick(fig) # callback = lambda event: plot_event.onclick(event))
1254
1255 plt.tight_layout()
1256 plt.pause(0.1)
1257
1258 print("")
1259 input("Press ENTER to terminate>>")
1260
1261
1262def correlation(inf, app, cparams):
1263 """
1264 入力された実験XRDパターンとCIFファイルから生成された理論パターンとの相関係数を計算し、可視化する。
1265
1266 詳細説明:
1267 実験XRDパターンと、読み込まれた各CIFファイルから計算された理論XRDパターン間の相関係数を計算し、
1268 結果をテキストで出力する。さらに、これらの相関係数をスマアリングFWHMを変化させながらプロットし、
1269 最も相関の高い相や適切なスマアリング条件を評価する。
1270
1271 :param inf: dict. 読み込まれたデータを含む辞書。
1272 :param app: tkApplicationのインスタンス。
1273 :param cparams: 設定パラメータを保持するオブジェクト。
1274 :returns: なし
1275 """
1276 print("")
1277 print("#########################################")
1278 print(" Check correlation between the input XRD and the cif XRD patterns")
1279 print("#########################################")
1280 print(f" smearing: fwhm={cparams.fwhm_smear} Gaussian fraction={cparams.Gfraction_smear}")
1281 inf_cif_list = inf["inf_cif_list"]
1282
1283 Q2_list, yobs_infile, ysim_infile, bg_names, bg_list, sample_names, ycif_list, labels_train, x_train = collect_data(inf, app, cparams)
1284 xlist = [yobs_infile]
1285 xlabels = ["obs"]
1286 xlist.extend(ycif_list)
1287 xlabels.extend(sample_names)
1288 nx = len(xlist)
1289 dx = Q2_list[1] - Q2_list[0]
1290
1291#相関係数
1292 print("")
1293 print("Correlation coefficients:")
1294 corr = np.zeros([nx, nx])
1295 for i in range(nx):
1296 for j in range(i, nx):
1297 corr[i][j] = np.dot(xlist[i], xlist[j])
1298 for i in range(nx):
1299 for j in range(i + 1, nx):
1300 corr[i][j] /= np.sqrt(corr[i][i] * corr[j][j])
1301 if corr[i][j] >= 0.9:
1302 print(f" identical? {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1303 elif corr[i][j] >= 0.8:
1304 print(f" similar {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1305 elif corr[i][j] >= 0.5:
1306 print(f" ***** {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1307 elif corr[i][j] >= 0.5:
1308 print(f" ***** {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1309 elif corr[i][j] >= 0.4:
1310 print(f" **** {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1311 elif corr[i][j] >= 0.3:
1312 print(f" *** {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1313 else:
1314 print(f" {corr[i][j]:8.4f}: ({i:2}-{j:2}): ({xlabels[i]:20})-({xlabels[j]:20})")
1315
1316# input dataとの相関係数をsmearing fwhmを変えながらプロット
1317 print("")
1318 print("Correlation coefficients with input data with varied smearing fwhm:")
1319 fwhm_smear_original = cparams.fwhm_smear
1320 fwhm_list = np.arange(0.0, 1.001, 0.2)
1321 corr_list = make_matrix2(nx, len(fwhm_list))
1322 for i in range(len(fwhm_list)):
1323 _fwhm = fwhm_list[i]
1324 cparams.fwhm_smear = _fwhm
1325 print("")
1326 print(f" Calculating for fwhm={_fwhm}")
1327 Q2_list0, yobs_infile0, ysim_infile0, bg_names0, bg_list0, sample_names0, ycif_list0, labels_train0, x_train0 \
1328 = collect_data(inf, app, cparams, is_print = False)
1329
1330 nskip = int((_fwhm / 5.0) / dx + 1.0e-5)
1331# nskip = 1
1332
1333 xlist0 = [[v for i, v in enumerate(yobs_infile0) if i % nskip == 0]]
1334 for y in ycif_list0:
1335 xlist0.append([v for i, v in enumerate(y) if i % nskip == 0])
1336# xlist0 = [yobs_infile]
1337# xlist0.extend(ycif_list0)
1338 nx_sampled = len(xlist0)
1339 print(f" _fwhm={_fwhm} dx={dx} nskip={nskip} nx={len(xlist0[0])}")
1340
1341 norm = make_matrix1(nx_sampled)
1342 for j in range(nx_sampled):
1343 print(f" calculating {j}-th diagonal norm")
1344 norm[j] = np.sqrt(np.dot(xlist0[j], xlist0[j]))
1345 for j in range(nx_sampled):
1346 print(f" calculating obs - {j}-th non-diagonal correlation")
1347 corr_list[j][i] = np.dot(xlist0[0], xlist0[j]) / norm[0] / norm[j]
1348
1349 cparams.fwhm_smear = fwhm_smear_original
1350
1351
1352 print("")
1353 print("plot")
1354
1355 fig, ax = plt.subplots(1, 1, figsize = figsize_one)
1356 plot_event = tkPlotEvent(plt, distance = 'x')
1357 ncolors = len(colors)
1358
1359 for i in range(1, nx): # "obs"を除いたCIFパターンとobsの相関をプロット
1360 ax.tick_params(labelsize = fontsize)
1361 ax.plot(fwhm_list, corr_list[i], label = xlabels[i], picker = True, color = colors[i % ncolors], linewidth = 1.0)
1362
1363 ax.legend(fontsize = legend_fontsize)
1364 ax.set_xlabel(r'smearing FWHM ($\degree$)', fontsize = fontsize)
1365 ax.set_ylabel(r'Correlation coefficient', fontsize = fontsize)
1366
1367 plot_event.register_pick(fig) # callback = lambda event: plot_event.onclick(event))
1368
1369 plt.tight_layout()
1370 plt.pause(0.1)
1371
1372 print("")
1373 input("Press ENTER to terminate>>")
1374
1375def fit(inf, app, cparams):
1376 """
1377 LASSO回帰を用いて実験XRDパターンを背景とCIF由来の理論パターンでフィッティングする。
1378
1379 詳細説明:
1380 実験XRDパターンを目的変数、背景多項式と各CIFファイルから計算された理論XRDパターンを説明変数として、
1381 LASSO回帰を実行する。異なるalpha値での係数変化とRMSEの変化をプロットし、最終的に指定されたalpha値での
1382 フィッティング結果(係数、RMSE、MAV)とフィッティングされたパターンをプロットで表示する。
1383
1384 :param inf: dict. 読み込まれたデータを含む辞書。
1385 :param app: tkApplicationのインスタンス。
1386 :param cparams: 設定パラメータを保持するオブジェクト。
1387 :returns: なし
1388 """
1389 print("")
1390 print("#########################################")
1391 print(" Fitting by LASSO")
1392 print("#########################################")
1393 print(f" alpha={cparams.alpha}")
1394 print(f" smearing: FWHM={cparams.fwhm_smear} Gaussian fraction={cparams.Gfraction_smear}")
1395 print("yscale:", cparams.yscale)
1396
1397 Q2_list, yobs_infile, ysim_infile, bg_names, bg_list, sample_names, ycif_list, labels_train, x_train \
1398 = collect_data(inf, app, cparams)
1399 nx = len(Q2_list)
1400 ncif = len(ycif_list)
1401 nxtrain = len(x_train)
1402
1403 print("")
1404 print("LASSO alpha:", cparams.alpha)
1405 x_train = np.array(x_train).T
1406
1407 alpha0 = 1.0e-8
1408 ntry = 80
1409 print("")
1410 print(f"Lasso regression with varied alpha: start from {alpha0}")
1411 # BG項のラベルも含むため、labels_trainの先頭から表示
1412 print(f"{'':42}", labels_train)
1413 _alpha = alpha0
1414 alpha_list = []
1415 c_list = []
1416 RMSE_list = []
1417 maxC = None
1418 for i in range(ntry):
1419 model = Lasso(alpha = _alpha, fit_intercept = False)
1420 model.fit(x_train, yobs_infile)
1421 yfit = model.predict(x_train)
1422 MSE = mean_squared_error(yobs_infile, yfit)
1423 RMSE = np.sqrt(MSE)
1424
1425 alpha_list.append(_alpha)
1426 c_list.append(model.coef_)
1427 RMSE_list.append(RMSE)
1428
1429 s = ["{:10.4g}".format(v) for v in model.coef_]
1430 s = " ".join(s)
1431 print(f" {i:2} alpha={_alpha:8.2g} RMSE={RMSE:12.4g} coeff={s}")
1432 if maxC is None:
1433 maxC = max(abs(max(model.coef_)), abs(min(model.coef_))) if len(model.coef_) > 0 else 0.0
1434 else:
1435 if len(model.coef_) > 0 and abs(max(model.coef_)) < 1.0e-5 * maxC and abs(min(model.coef_)) < 1.0e-5 * maxC:
1436 break
1437
1438 _alpha *= 2.0
1439
1440 plot_event = tkPlotEvent(plt, distance = 'x')
1441
1442 print("")
1443 print("plot LASSO analysis")
1444 # coeffプロットはBG項も含めて全係数を表示するが、凡例はCIF名のみ
1445 print("sample_names=", sample_names)
1446 fig_lasso = plt.figure(figsize = figsize_coeff)
1447 ax = fig_lasso.add_subplot(1, 1, 1)
1448 ax2 = ax.twinx()
1449 ax.tick_params(labelsize = fontsize)
1450 ax2.tick_params(labelsize = fontsize)
1451
1452 ax.plot(alpha_list, RMSE_list, label = 'RMSE', picker = True, linestyle = 'dashed', color = 'black', linewidth = 1.5)
1453
1454 # BG項の係数もプロットする場合
1455 # for j in range(len(bg_names)):
1456 # ax2.plot(alpha_list, np.array(c_list).T[j], label = bg_names[j], picker = True, linewidth = 0.8, linestyle = 'dotted')
1457
1458 # CIF項の係数をプロット
1459 for i in range(len(sample_names)):
1460 # model.coef_ のうち、CIF成分に対応するインデックスは BGorder + 1 以降
1461 ax2.plot(alpha_list, np.array(c_list).T[cparams.BGorder + 1 + i], label = sample_names[i], picker = True, linewidth = 1.0, color = colors[i % ncolors])
1462 ax2.axhline(0.0, linestyle = 'dashed', color = 'red', linewidth = 0.5)
1463
1464 ax.set_xlabel('alpha', fontsize = fontsize)
1465 ax.set_ylabel('RMSE', fontsize = fontsize)
1466 ax2.set_ylabel('coefficient', fontsize = fontsize)
1467 ax.set_xscale('log')
1468 ax.set_yscale('log')
1469 ax2.legend(fontsize = legend_fontsize_one)
1470
1471 plt.tight_layout()
1472 plt.pause(0.1)
1473
1474 model = Lasso(alpha = cparams.alpha, fit_intercept = False)
1475 model.fit(x_train, yobs_infile)
1476 yfit = model.predict(x_train)
1477
1478 print("")
1479 print(f"Lasso regression with alpha={cparams.alpha}")
1480 print(f" Coefficients:")
1481# print(f" coefficients:", model.coef_)
1482 yBG = np.zeros(nx)
1483 for order in range(cparams.BGorder + 1):
1484 print(f" {bg_names[order]}: {model.coef_[order]:10.6g}")
1485 yBG += model.coef_[order] * bg_list[order] # BG多項式の寄与を計算
1486
1487 # CIF項の係数と、それらを乗じたパターンを更新
1488 for i in range(len(sample_names)):
1489 c = model.coef_[cparams.BGorder + 1 + i] # BG項の後にCIF項が続く
1490 print(f" {sample_names[i]:20}: {c:10.6g}")
1491 # collect_dataでycif_listは正規化された状態なので、ここで係数を乗じる
1492 ycif_list[i] *= c
1493
1494 MAE = mean_absolute_error(yobs_infile, yfit)
1495 MSE = mean_squared_error(yobs_infile, yfit)
1496 RMSE = np.sqrt(MSE)
1497 print(f" MAE : {MAE:12.4g}")
1498 print(f" MSE : {MSE:12.4g}")
1499 print(f" RMSE: {RMSE:12.4g}")
1500
1501 print("")
1502 print("plot XRD profiles")
1503 fig = plt.figure(figsize = figsize_one)
1504 ncolors = len(colors)
1505 ax = fig.add_subplot(1, 1, 1)
1506 ax.tick_params(labelsize = fontsize)
1507
1508 ax.plot(Q2_list, yobs_infile, label = "obs", picker = True, linestyle = '',
1509 marker = 'o', markersize = 2.0, markerfacecolor = colors[0], markeredgecolor = colors[0])
1510 ax.plot(Q2_list, yBG, label = "background", picker = True, linestyle = '-', color = 'cyan', linewidth = 0.5)
1511# ax.plot(Q2_list, yobs_infile, label = "obs", color = colors[0], linewidth = 1.5)
1512 ax.plot(Q2_list, yfit, label = "fit", picker = True, linestyle = 'dashed', color = colors[1], linewidth = 1.5)
1513# ax.plot(Q2_list, ysim_infile, label = "obs", color = colors[1], linewidth = 0.5)
1514 # フィッティングされた各CIFパターンをプロット
1515 for i in range(len(sample_names)):
1516 ax.plot(Q2_list, ycif_list[i], label = f"{sample_names[i]}", picker = True, color = colors[(i+2) % ncolors ], linewidth = 1.2) # +2 は obs, fit, BGを避けるため
1517
1518# for order in range(cparams.BGorder):
1519# ax.plot(Q2_list, bg_list[order], label = f"{order+1}-th order", color = colors[(ncif+2+order) % ncolors], linewidth = 0.5)
1520
1521 ax.set_xlabel('$2\\theta$', fontsize = fontsize)
1522 if cparams.yscale == 'log':
1523 ax.set_ylabel('log($y$)', fontsize = fontsize)
1524 else:
1525 ax.set_ylabel('$y$', fontsize = fontsize)
1526 ax.legend(fontsize = legend_fontsize_one)
1527
1528 plot_event.register_pick(fig_lasso) # callback = lambda event: plot_event.onclick(event))
1529 plot_event.register_pick(fig) # callback = lambda event: plot_event.onclick(event))
1530
1531
1532 plt.tight_layout()
1533 plt.pause(0.1)
1534
1535 input("Press ENTER to terminate>>")
1536
1537def main():
1538 """
1539 メイン関数。XRD解析スクリプトのエントリポイント。
1540
1541 詳細説明:
1542 アプリケーションの初期化、パラメータの読み込みと更新、プラグインモジュールのロード、
1543 および指定されたモードに応じたXRD解析処理(プロット、相関分析、フィッティングなど)を実行する。
1544 処理のログはファイルにも出力される。
1545
1546 :returns: なし
1547 """
1548 global module_names, modules
1549
1550#==================================================================
1551# Initialize parameters
1552#==================================================================
1553 app = tkApplication(usage_str = usage_str, globals = globals(), locals = locals())
1554 cparams = app.get_params()
1555
1556 logfile = app.replace_path(None, template = ["{dirname}", "{filebody}-out.txt"])
1557# logfile = app.replace_path(cparams.infile, template = ["{dirname}", "{filebody}-out.txt"])
1558 print(f"Open logfile [{logfile}]")
1559 app.redirect(targets = ["stdout", logfile], mode = 'w')
1560
1561 initialize(app, cparams)
1562 update_vars(app, cparams)
1563
1564 cparams.outfile = replace_path(cparams.infile, template = os.path.join("{dirname}", "{filebody}-out.txt"))
1565
1566 print("")
1567 print( "==========================================================================")
1568 print(" Convert CIF file to powder XRD pattern")
1569 print( "==========================================================================")
1570 print(f"mode: {cparams.mode}")
1571 print(f"Plug-in dir: {cparams.plugin_dir}")
1572 print(f"Input file: {cparams.infile}")
1573 print(f"Output file: {cparams.outfile}")
1574
1575# Load modules
1576 print("")
1577 print(f"Load modules:")
1578 module_names, modules = app.load_modules(cparams.plugin_dir, "*.py", target = "read_data", is_print = True)
1579 for m in modules:
1580# if hasattr(m, "initialize"):
1581# print(f"initialize {m.name}")
1582# m.initialize(app, cparams)
1583 input_type = m.get_input_type(app = app, cparams = cparams)
1584 output_type = m.get_output_type(app = app, cparams = cparams)
1585 print(f" {m.name}: input_type={input_type} output_type={output_type}")
1586
1587 if cparams.mode == 'plot':
1588 inf = read_all_files(app, cparams, input_only = True)
1589 plot_input(inf, app, cparams)
1590 elif cparams.mode == 'overwrap':
1591 inf = read_all_files(app, cparams)
1592 check_overwrap(inf, app, cparams)
1593 elif cparams.mode == 'CIFcorrelation':
1594 inf = read_all_files(app, cparams)
1595 CIF_correlation(inf, app, cparams)
1596 elif cparams.mode == 'correlation':
1597 inf = read_all_files(app, cparams)
1598 correlation(inf, app, cparams)
1599 elif cparams.mode == 'plot_all':
1600 inf = read_all_files(app, cparams)
1601 plot_all(inf, app, cparams)
1602 elif cparams.mode == 'plot_one':
1603 inf = read_all_files(app, cparams)
1604 plot_one(inf, app, cparams)
1605 elif cparams.mode == 'plot_one2':
1606 inf = read_all_files(app, cparams)
1607 plot_one2(inf, app, cparams)
1608 elif cparams.mode == 'fit':
1609 inf = read_all_files(app, cparams)
1610 fit(inf, app, cparams)
1611
1612 app.terminate(usage = usage)
1613
1614
1615if __name__ == "__main__":
1616 main()