Enable Fit/Int area selector

This commit is contained in:
usov_i 2021-05-20 12:00:53 +02:00
parent 09d22e7674
commit 0b6a58e160
4 changed files with 73 additions and 71 deletions

View File

@ -43,7 +43,7 @@ from bokeh.models import (
) )
import pyzebra import pyzebra
from pyzebra.ccl_io import AREA_METHODS from pyzebra.ccl_process import AREA_METHODS
javaScript = """ javaScript = """
@ -467,6 +467,11 @@ def create():
pyzebra.fit_scan( pyzebra.fit_scan(
scan, fit_params, fit_from=fit_from_spinner.value, fit_to=fit_to_spinner.value 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_plot(_get_selected_scan())
_update_table() _update_table()
@ -479,6 +484,11 @@ def create():
pyzebra.fit_scan( pyzebra.fit_scan(
scan, fit_params, fit_from=fit_from_spinner.value, fit_to=fit_to_spinner.value 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_plot(scan)
_update_table() _update_table()
@ -486,19 +496,9 @@ def create():
fit_button = Button(label="Fit Current", width=145) fit_button = Button(label="Fit Current", width=145)
fit_button.on_click(fit_button_callback) fit_button.on_click(fit_button_callback)
def area_method_radiobutton_callback(_handler): area_method_radiobutton = RadioButtonGroup(labels=["Fit area", "Int area"], active=0, width=145)
_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()
lorentz_checkbox = CheckboxGroup(labels=["Lorentz Correction"], width=145, margin=[13, 5, 5, 5]) 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) export_preview_textinput = TextAreaInput(title="Export file preview:", width=500, height=400)
@ -511,11 +511,7 @@ def create():
export_data.append(s) export_data.append(s)
pyzebra.export_1D( pyzebra.export_1D(
export_data, export_data, temp_file, hkl_precision=int(hkl_precision_select.value),
temp_file,
area_method=AREA_METHODS[int(area_method_radiobutton.active)],
lorentz=bool(lorentz_checkbox.active),
hkl_precision=int(hkl_precision_select.value),
) )
exported_content = "" exported_content = ""

View File

@ -48,7 +48,7 @@ from bokeh.palettes import Category10, Turbo256
from bokeh.transform import linear_cmap from bokeh.transform import linear_cmap
import pyzebra import pyzebra
from pyzebra.ccl_io import AREA_METHODS from pyzebra.ccl_process import AREA_METHODS
javaScript = """ javaScript = """
for (let i = 0; i < js_data.data['fname'].length; i++) { for (let i = 0; i < js_data.data['fname'].length; i++) {
@ -557,6 +557,11 @@ def create():
pyzebra.fit_scan( pyzebra.fit_scan(
scan, fit_params, fit_from=fit_from_spinner.value, fit_to=fit_to_spinner.value 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_plot()
_update_table() _update_table()
@ -569,6 +574,11 @@ def create():
pyzebra.fit_scan( pyzebra.fit_scan(
scan, fit_params, fit_from=fit_from_spinner.value, fit_to=fit_to_spinner.value 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_plot()
_update_table() _update_table()
@ -576,19 +586,9 @@ def create():
fit_button = Button(label="Fit Current", width=145) fit_button = Button(label="Fit Current", width=145)
fit_button.on_click(fit_button_callback) fit_button.on_click(fit_button_callback)
def area_method_radiobutton_callback(_handler): area_method_radiobutton = RadioButtonGroup(labels=["Fit area", "Int area"], active=0, width=145)
_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()
lorentz_checkbox = CheckboxGroup(labels=["Lorentz Correction"], width=145, margin=[13, 5, 5, 5]) 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) export_preview_textinput = TextAreaInput(title="Export file preview:", width=450, height=400)
@ -600,12 +600,7 @@ def create():
if export: if export:
export_data.append(s) export_data.append(s)
pyzebra.export_1D( pyzebra.export_1D(export_data, temp_file)
export_data,
temp_file,
area_method=AREA_METHODS[int(area_method_radiobutton.active)],
lorentz=bool(lorentz_checkbox.active),
)
exported_content = "" exported_content = ""
file_content = [] file_content = []

View File

@ -3,7 +3,6 @@ import re
from collections import defaultdict from collections import defaultdict
import numpy as np import numpy as np
from scipy.integrate import simpson, trapezoid
META_VARS_STR = ( META_VARS_STR = (
"instrument", "instrument",
@ -77,8 +76,6 @@ CCL_SECOND_LINE = (
("scan_motor", str), ("scan_motor", str),
) )
AREA_METHODS = ("fit_area", "int_area")
def load_1D(filepath): def load_1D(filepath):
""" """
@ -244,7 +241,7 @@ def parse_1D(fileobj, data_type):
return scan 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 """Exports data in the .comm/.incomm format
Scans with integer/real hkl values are saved in .comm/.incomm files correspondingly. If no scans 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: else:
hkl_str = f"{h:8.{hkl_precision}f}{k:8.{hkl_precision}f}{l:8.{hkl_precision}f}" 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(): area_n, area_s = scan["area"]
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_str = f"{area_n:10.2f}{area_s:10.2f}" area_str = f"{area_n:10.2f}{area_s:10.2f}"
ang_str = "" ang_str = ""

View File

@ -3,6 +3,7 @@ import os
import numpy as np import numpy as np
from lmfit.models import GaussianModel, LinearModel, PseudoVoigtModel, VoigtModel from lmfit.models import GaussianModel, LinearModel, PseudoVoigtModel, VoigtModel
from scipy.integrate import simpson, trapezoid
from .ccl_io import CCL_ANGLES from .ccl_io import CCL_ANGLES
@ -22,6 +23,8 @@ MAX_RANGE_GAP = {
"omega": 0.5, "omega": 0.5,
} }
AREA_METHODS = ("fit_area", "int_area")
def normalize_dataset(dataset, monitor=100_000): def normalize_dataset(dataset, monitor=100_000):
for scan in dataset: 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] 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) 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)