"""
多重ピークフィッティングモジュール
このモジュールは、複数のピークを持つデータセットに対し、最適化されたフィッティングを実行するための
メインスクリプトを提供します。データ入力、初期条件設定、様々なフィッティングアルゴリズム、
結果のプロットといった機能を含みます。
:doc:`optimize_peakfit_usage`
"""
import os
import platform
import sys
import re
sys.path.append('.')
try:
import tklib.tkimport as imp
except Exception as e:
print()
print("######################################################################")
print("########### ERROR ERROR ERROR ERROR ERROR ERROR #####################")
print("######################################################################")
print(f"# Failed to import [tklib.tkimport] module ({e}).")
print(f"# Add [tkProg]{os.sep}tklib{os.sep}python to PYTHONPATH variable")
print(f"# Current PYTHONPATH:", sys.path)
print("######################################################################")
input("Press ENTER to terminate>>")
exit()
np = imp.import_lib("numpy", stop_by_error = False)
pd = imp.import_lib("pandas", stop_by_error = False)
mpl = imp.import_lib("matplotlib", stop_by_error = False)
imp.messages(stop_by_error = True)
from numpy import sqrt, exp, log, log10
from scipy.optimize import minimize
from scipy.signal import savgol_filter
from matplotlib import pyplot as plt
import pandas
from tklib.tkutils import print_data, pint, pfloat, format_strlist
from tklib.tkvariousdata import tkVariousData
from tklib.tkapplication import tkApplication
from tklib.tkparams import tkParams
from tklib.tksci.tksci import e, kB
from tklib.tksci.tkmlr import tkMLData, tkMLR
from tklib.tkgraphic.tkplot_pyplot import select_plt, tkPlot_pyplot
from tklib.tkgraphic.tkplotevent import tkPlotEvent, RangeSelector
from tklib.tksci.tkFit_lib import conv_input, save_data, add_history
import tklib.tksci.tkoptimize_flex as opt
import optimize_peakfit_mf as mf
import peakfit as omodel
ProgramName = "Fitting to multiple peaks"
[ドキュメント]
def init(app, cfg, mf):
"""
ピークフィッティングの初期条件を設定し、線形最小二乗法で初期フィッティングを実行します。
入力データと設定ファイルに基づいてフィッティングパラメータを構築し、
初期の線形フィッティングを実行して、ピークの初期位置と強度を推定します。
結果は設定オブジェクトに保存されます。
:param app: tkApplicationインスタンス。アプリケーションの状態とユーティリティを提供します。
:type app: tklib.tkapplication.tkApplication
:param cfg: tkParamsインスタンス。プログラムの設定パラメータを保持します。
:type cfg: tklib.tkparams.tkParams
:param mf: optimize_peakfit_mfモジュールのインスタンス。フィッティング関連のヘルパー関数を提供します。
:type mf: module
:returns: None
"""
print("")
print("Initialize fitting condition:")
fit = opt.clean(app, cfg, mf)
config_path = cfg.parameterfile
fitparam_path = fit.fitfile_path
print(f" Read [{cfg.infile}]")
xlabels, ylabels, xdata_list, ydata_list, _ = mf.read_input_data(app, cfg.infile, cfg = cfg)
xlist = xdata_list[0]
ylist = ydata_list[0]
options = {"nsmooth": cfg.nsmooth, "norder": cfg.norder, "threshold": cfg.threshold, "ydiff1_threshold": cfg.ydiff1_threshold}
app.varname, app.unit, app.pk_scale, app.optid, app.linid, app.x0, app.dx, app.kmin, app.kmax, app.kpenalty \
= omodel.build_fit_params(xlist, ylist, options)
for i, varname in enumerate(app.varname):
app.add_argument(opt = f"--{varname}", type = "float", defval = app.x0[i])
print()
fit = mf.init_fit(app, cfg)
# Linear LSQ
pk_all = opt.linear_fit(app, cfg, mf, omodel, fit, print_level = True)
fit.pk = pk_all
print()
mf.save_parameter_files(config_path, fitparam_path, fit, cfg)
app.terminate(pause = True)
[ドキュメント]
def main():
"""
プログラムのメインエントリポイント。
コマンドライン引数の解析、設定ファイルの読み込み、ログのセットアップを行い、
`cfg.mode` パラメータに基づいて適切なフィッティングまたはデータ処理モードを呼び出します。
`mk_config` モードでは設定ファイルを作成します。
:returns: None
"""
app = tkApplication()
if len(sys.argv) > 1 and sys.argv[1] == 'mk_config':
app.make_config_files(arg_config_file = 'arg_config.xlsx', fit_config_file = 'fit_config.xlsx')
app.terminate("\n", pause = True)
#初期値の確定順序
#intialize(): 起動時引数と初期値の設定
cfg = mf.initialize(app)
#--infile引数をチェックし、読み込みファイル名を最初に確定する
cfg.infile = app.check_arg('--infile', defval = None, vartype = 'str')
#cfg.infileからログファイル名を作り、console出力をredirectする
cfg.logfile = app.replace_path(cfg.infile)
app.redirect(heading = f"Open logfile [{cfg.logfile}]",
targets = ["stdout", cfg.logfile], mode = 'w')
app.set_exception()
try:
app.print_title(f"# {ProgramName}")
except:
pass
#cfg.infileが入力ファイルか設定ファイルであるかによって、infileとconfig_pathを返す
# 設定ファイルである場合、infile_storedをNoneにして、後で設定ファイルからcfg.infileを読み込む
cfg.infile, cfg.parameterfile, infile_stored \
= app.analyze_infile(cfg.infile, infile_ext = [".xlsx"], config_ext = [".in", ".ini", ".prm"], print_level = 1)
#起動時引数で与えられたパラメータをcfgに設定
print()
print("Update parameters from command line arguments")
app.update_vars(cfg, apply_default = True)
# cfg.print_parameters()
mf.initialize_minimize_func(app)
#設定ファイルを読み込み、cfgに設定。#cfg.infileも書き換えられる
print()
print(f"Read configration file [{cfg.parameterfile}]")
mf.read_parameters(cfg.parameterfile, cfg)
# cfg.print_parameters()
#infile_stored = Noneの場合、設定ファイルのcfg.infileをinfile_storedに再保存
#infile_storedが最終的な読み込みファイル名になる
if infile_stored is None: infile_stored = cfg.infile
#起動時引数で与えられたパラメータを最優先にするため、再設定
app.force_given_args(cfg)
# cfg.print_parameters()
# exit()
# --daemonフラグが立っていたらdaemonize()
if cfg.get("daemon", 0):
print("\ndaemon flag is set:")
print(" fplot flag is set to -1")
cfg.fplot = -1
app.daemonize(stdout_path = 'daemon.log', stderr_path = 'daemon.log', print_level = 1)
# --nohupフラグが立っていたらHUPシグナルを無視
if cfg.get("nohup", 0): app.nohup()
#cfg.infileを infile_storedに最終設定
cfg.infile = infile_stored
cfg.print_parameters()
# exit()
cfg.historyfile = app.replace_path(cfg.infile, template = ["{dirname}", "{filebody}-history.xlsx"])
cfg.stopfile = app.replace_path(cfg.infile, template = ["{dirname}", "stop"])
print(f"infile: {cfg.infile}")
print(f"parameterfile: {cfg.parameterfile}")
print(f"stop file: {cfg.stopfile}")
if os.path.isfile(cfg.stopfile):
print(f"\nWarning: stop file [{cfg.stopfile}] exisits")
print(" remove it")
os.remove(cfg.stopfile)
if cfg.file1 in ['clean', 'inf', 'kill', 'plot', 'init', 'search', 'lfit', 'lasso', 'fit', 'update', 'sim', "error"]:
cfg.mode = cfg.file1
cfg.file1 = ''
if cfg.mode == 'clean':
opt.clean(app, cfg, mf)
elif cfg.mode == 'kill':
opt.kill(app, 'python')
elif cfg.mode == 'inf':
opt.inf(app, cfg, mf)
elif cfg.mode == 'init':
init(app, cfg, mf)
elif cfg.mode == 'search':
omodel.peak_search(app, cfg, mf)
elif cfg.mode == 'lfit':
opt.linear_fit_func(app, cfg, mf, omodel)
elif cfg.mode == 'lasso':
opt.lasso(app, cfg, mf, omodel)
elif cfg.mode == 'sim':
opt.sim(app, cfg, mf)
elif cfg.mode == 'scan':
opt.scan(app, cfg, mf)
elif cfg.mode == 'mapping':
opt.mapping(app, cfg, mf)
elif cfg.mode == 'sampling':
opt.sampling(app, cfg, mf)
elif cfg.mode == 'fit1':
opt.fit1(app, cfg, mf)
elif cfg.mode == 'fit':
if cfg.get("daemon", 0):
opt.fit_simple(app, cfg, mf, optid_mode = 'optid')
else:
opt.fit(app, cfg, mf, optid_mode = 'optid')
elif cfg.mode == 'fitlp':
if cfg.get("daemon", 0):
opt.fit_simple(app, cfg, mf, optid_mode = 'linid')
else:
opt.fit(app, cfg, mf, optid_mode = 'linid')
elif cfg.mode == 'error':
opt.error(app, cfg, mf)
elif cfg.mode == 'mlr':
opt.mlr(app, cfg, mf)
elif cfg.mode == 'plot':
omodel.plot_input(app, cfg, mf)
elif cfg.mode == 'plot_history':
plot_history(app, cfg, mf)
elif cfg.mode == 'plot_fit':
plot_fit(app, cfg, mf)
elif cfg.mode in globals() and callable(globals()[cfg.mode]):
# cfg.modeで与えられた関数が定義されていれば、呼び出す
globals()[cfg.mode](app, cfg)
else:
app.terminate(message = "\n",
usage = app.usage,
post_message = f"Error in main: Invalide mode [{cfg.mode}]",
pause = True,
)
if __name__ == "__main__":
main()