From 0b6a58e160508d2940f3179dc56cf4c00bf241ce Mon Sep 17 00:00:00 2001 From: Ivan Usov Date: Thu, 20 May 2021 12:00:53 +0200 Subject: [PATCH] Enable Fit/Int area selector --- pyzebra/app/panel_ccl_integrate.py | 30 +++++++++----------- pyzebra/app/panel_param_study.py | 31 +++++++++----------- pyzebra/ccl_io.py | 38 ++----------------------- pyzebra/ccl_process.py | 45 ++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 71 deletions(-) diff --git a/pyzebra/app/panel_ccl_integrate.py b/pyzebra/app/panel_ccl_integrate.py index 3e832d5..0ee3495 100644 --- a/pyzebra/app/panel_ccl_integrate.py +++ b/pyzebra/app/panel_ccl_integrate.py @@ -43,7 +43,7 @@ from bokeh.models import ( ) import pyzebra -from pyzebra.ccl_io import AREA_METHODS +from pyzebra.ccl_process import AREA_METHODS javaScript = """ @@ -467,6 +467,11 @@ def create(): pyzebra.fit_scan( scan, fit_params, fit_from=fit_from_spinner.value, fit_to=fit_to_spinner.value ) + pyzebra.get_area( + scan, + area_method=AREA_METHODS[area_method_radiobutton.active], + lorentz=lorentz_checkbox.active, + ) _update_plot(_get_selected_scan()) _update_table() @@ -479,6 +484,11 @@ def create(): pyzebra.fit_scan( scan, fit_params, fit_from=fit_from_spinner.value, fit_to=fit_to_spinner.value ) + pyzebra.get_area( + scan, + area_method=AREA_METHODS[area_method_radiobutton.active], + lorentz=lorentz_checkbox.active, + ) _update_plot(scan) _update_table() @@ -486,19 +496,9 @@ def create(): fit_button = Button(label="Fit Current", width=145) fit_button.on_click(fit_button_callback) - def area_method_radiobutton_callback(_handler): - _update_preview() - - area_method_radiobutton = RadioButtonGroup( - labels=["Fit area", "Int area"], active=0, width=145, disabled=True - ) - area_method_radiobutton.on_click(area_method_radiobutton_callback) - - def lorentz_checkbox_callback(_handler): - _update_preview() + area_method_radiobutton = RadioButtonGroup(labels=["Fit area", "Int area"], active=0, width=145) lorentz_checkbox = CheckboxGroup(labels=["Lorentz Correction"], width=145, margin=[13, 5, 5, 5]) - lorentz_checkbox.on_click(lorentz_checkbox_callback) export_preview_textinput = TextAreaInput(title="Export file preview:", width=500, height=400) @@ -511,11 +511,7 @@ def create(): export_data.append(s) pyzebra.export_1D( - export_data, - temp_file, - area_method=AREA_METHODS[int(area_method_radiobutton.active)], - lorentz=bool(lorentz_checkbox.active), - hkl_precision=int(hkl_precision_select.value), + export_data, temp_file, hkl_precision=int(hkl_precision_select.value), ) exported_content = "" diff --git a/pyzebra/app/panel_param_study.py b/pyzebra/app/panel_param_study.py index a344225..2f1edcd 100644 --- a/pyzebra/app/panel_param_study.py +++ b/pyzebra/app/panel_param_study.py @@ -48,7 +48,7 @@ from bokeh.palettes import Category10, Turbo256 from bokeh.transform import linear_cmap import pyzebra -from pyzebra.ccl_io import AREA_METHODS +from pyzebra.ccl_process import AREA_METHODS javaScript = """ for (let i = 0; i < js_data.data['fname'].length; i++) { @@ -557,6 +557,11 @@ def create(): pyzebra.fit_scan( scan, fit_params, fit_from=fit_from_spinner.value, fit_to=fit_to_spinner.value ) + pyzebra.get_area( + scan, + area_method=AREA_METHODS[area_method_radiobutton.active], + lorentz=lorentz_checkbox.active, + ) _update_plot() _update_table() @@ -569,6 +574,11 @@ def create(): pyzebra.fit_scan( scan, fit_params, fit_from=fit_from_spinner.value, fit_to=fit_to_spinner.value ) + pyzebra.get_area( + scan, + area_method=AREA_METHODS[area_method_radiobutton.active], + lorentz=lorentz_checkbox.active, + ) _update_plot() _update_table() @@ -576,19 +586,9 @@ def create(): fit_button = Button(label="Fit Current", width=145) fit_button.on_click(fit_button_callback) - def area_method_radiobutton_callback(_handler): - _update_preview() - - area_method_radiobutton = RadioButtonGroup( - labels=["Fit area", "Int area"], active=0, width=145, disabled=True - ) - area_method_radiobutton.on_click(area_method_radiobutton_callback) - - def lorentz_checkbox_callback(_handler): - _update_preview() + area_method_radiobutton = RadioButtonGroup(labels=["Fit area", "Int area"], active=0, width=145) lorentz_checkbox = CheckboxGroup(labels=["Lorentz Correction"], width=145, margin=[13, 5, 5, 5]) - lorentz_checkbox.on_click(lorentz_checkbox_callback) export_preview_textinput = TextAreaInput(title="Export file preview:", width=450, height=400) @@ -600,12 +600,7 @@ def create(): if export: export_data.append(s) - pyzebra.export_1D( - export_data, - temp_file, - area_method=AREA_METHODS[int(area_method_radiobutton.active)], - lorentz=bool(lorentz_checkbox.active), - ) + pyzebra.export_1D(export_data, temp_file) exported_content = "" file_content = [] diff --git a/pyzebra/ccl_io.py b/pyzebra/ccl_io.py index 247a84f..bf27d6f 100644 --- a/pyzebra/ccl_io.py +++ b/pyzebra/ccl_io.py @@ -3,7 +3,6 @@ import re from collections import defaultdict import numpy as np -from scipy.integrate import simpson, trapezoid META_VARS_STR = ( "instrument", @@ -77,8 +76,6 @@ CCL_SECOND_LINE = ( ("scan_motor", str), ) -AREA_METHODS = ("fit_area", "int_area") - def load_1D(filepath): """ @@ -244,7 +241,7 @@ def parse_1D(fileobj, data_type): return scan -def export_1D(data, path, area_method=AREA_METHODS[0], lorentz=False, hkl_precision=2): +def export_1D(data, path, hkl_precision=2): """Exports data in the .comm/.incomm format Scans with integer/real hkl values are saved in .comm/.incomm files correspondingly. If no scans @@ -266,38 +263,7 @@ def export_1D(data, path, area_method=AREA_METHODS[0], lorentz=False, hkl_precis else: hkl_str = f"{h:8.{hkl_precision}f}{k:8.{hkl_precision}f}{l:8.{hkl_precision}f}" - for name, param in scan["fit"].params.items(): - if "amplitude" in name: - if param.stderr is None: - area_n = np.nan - area_s = np.nan - else: - area_n = param.value - area_s = param.stderr - # TODO: take into account multiple peaks - break - else: - # no peak functions in a fit model - # assume this is a background fit, so do numeric integration - y_val = scan["Counts"] - x_val = scan[scan["scan_motor"]] - y_bkg = scan["fit"].eval(x=x_val) - area_n = simpson(y_val, x=x_val) - trapezoid(y_bkg, x=x_val) - area_s = np.sqrt(area_n) - - # apply lorentz correction to area - if lorentz: - if zebra_mode == "bi": - twotheta = np.deg2rad(scan["twotheta"]) - corr_factor = np.sin(twotheta) - else: # zebra_mode == "nb": - gamma = np.deg2rad(scan["gamma"]) - nu = np.deg2rad(scan["nu"]) - corr_factor = np.sin(gamma) * np.cos(nu) - - area_n = np.abs(area_n * corr_factor) - area_s = np.abs(area_s * corr_factor) - + area_n, area_s = scan["area"] area_str = f"{area_n:10.2f}{area_s:10.2f}" ang_str = "" diff --git a/pyzebra/ccl_process.py b/pyzebra/ccl_process.py index 6af7844..e4fa860 100644 --- a/pyzebra/ccl_process.py +++ b/pyzebra/ccl_process.py @@ -3,6 +3,7 @@ import os import numpy as np from lmfit.models import GaussianModel, LinearModel, PseudoVoigtModel, VoigtModel +from scipy.integrate import simpson, trapezoid from .ccl_io import CCL_ANGLES @@ -22,6 +23,8 @@ MAX_RANGE_GAP = { "omega": 0.5, } +AREA_METHODS = ("fit_area", "int_area") + def normalize_dataset(dataset, monitor=100_000): for scan in dataset: @@ -148,3 +151,45 @@ def fit_scan(scan, model_dict, fit_from=None, fit_to=None): weights = [1 / np.sqrt(val) if val != 0 else 1 for val in y_fit] scan["fit"] = model.fit(y_fit, x=x_fit, weights=weights) + + +def get_area(scan, area_method, lorentz): + if area_method not in AREA_METHODS: + raise ValueError(f"Unknown area method: {area_method}.") + + if area_method == "fit_area": + for name, param in scan["fit"].params.items(): + if "amplitude" in name: + if param.stderr is None: + area_n = np.nan + area_s = np.nan + else: + area_n = param.value + area_s = param.stderr + # TODO: take into account multiple peaks + break + else: + area_n = np.nan + area_s = np.nan + + else: # area_method == "int_area" + y_val = scan["Counts"] + x_val = scan[scan["scan_motor"]] + y_bkg = scan["fit"].eval_components(x=x_val)["f0_"] + area_n = simpson(y_val, x=x_val) - trapezoid(y_bkg, x=x_val) + area_s = np.sqrt(area_n) + + if lorentz: + # lorentz correction to area + if scan["zebra_mode"] == "bi": + twotheta = np.deg2rad(scan["twotheta"]) + corr_factor = np.sin(twotheta) + else: # zebra_mode == "nb": + gamma = np.deg2rad(scan["gamma"]) + nu = np.deg2rad(scan["nu"]) + corr_factor = np.sin(gamma) * np.cos(nu) + + area_n = np.abs(area_n * corr_factor) + area_s = np.abs(area_s * corr_factor) + + scan["area"] = (area_n, area_s)