Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
a2fceffc1b | |||
415d68b4dc | |||
00ff4117ea | |||
67853b8db4 | |||
60787bccb7 | |||
880d86d750 | |||
7a88e5e254 | |||
20f2a8ada4 | |||
42c092fc14 | |||
8153db9f67 | |||
62c969d6ad | |||
085620abae | |||
9ebe290966 | |||
c9cd96c521 | |||
d745cda4a5 | |||
1b5f70afa0 | |||
a034065a09 | |||
2a60c86b48 | |||
ccc075975f |
1
.github/workflows/deployment.yaml
vendored
1
.github/workflows/deployment.yaml
vendored
@ -16,6 +16,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
$CONDA/bin/conda install --quiet --yes conda-build anaconda-client
|
$CONDA/bin/conda install --quiet --yes conda-build anaconda-client
|
||||||
$CONDA/bin/conda config --append channels conda-forge
|
$CONDA/bin/conda config --append channels conda-forge
|
||||||
|
$CONDA/bin/conda config --set channel_priority strict
|
||||||
$CONDA/bin/conda config --set anaconda_upload yes
|
$CONDA/bin/conda config --set anaconda_upload yes
|
||||||
|
|
||||||
- name: Build and upload
|
- name: Build and upload
|
||||||
|
@ -4,4 +4,4 @@ from pyzebra.h5 import *
|
|||||||
from pyzebra.xtal import *
|
from pyzebra.xtal import *
|
||||||
from pyzebra.ccl_process import *
|
from pyzebra.ccl_process import *
|
||||||
|
|
||||||
__version__ = "0.3.1"
|
__version__ = "0.3.2"
|
||||||
|
@ -23,12 +23,13 @@ REFLECTION_PRINTER_FORMATS = [
|
|||||||
ALGORITHMS = ["adaptivemaxcog", "adaptivedynamic"]
|
ALGORITHMS = ["adaptivemaxcog", "adaptivedynamic"]
|
||||||
|
|
||||||
|
|
||||||
def anatric(config_file, anatric_path="/afs/psi.ch/project/sinq/rhel7/bin/anatric"):
|
def anatric(config_file, anatric_path="/afs/psi.ch/project/sinq/rhel7/bin/anatric", cwd=None):
|
||||||
comp_proc = subprocess.run(
|
comp_proc = subprocess.run(
|
||||||
[anatric_path, config_file],
|
[anatric_path, config_file],
|
||||||
check=True,
|
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.STDOUT,
|
stderr=subprocess.STDOUT,
|
||||||
|
cwd=cwd,
|
||||||
|
check=True,
|
||||||
text=True,
|
text=True,
|
||||||
)
|
)
|
||||||
print(" ".join(comp_proc.args))
|
print(" ".join(comp_proc.args))
|
||||||
@ -59,10 +60,13 @@ class AnatricConfig:
|
|||||||
def save_as(self, filename):
|
def save_as(self, filename):
|
||||||
self._tree.write(filename)
|
self._tree.write(filename)
|
||||||
|
|
||||||
|
def tostring(self):
|
||||||
|
return ET.tostring(self._tree.getroot(), encoding="unicode")
|
||||||
|
|
||||||
def _get_attr(self, name, tag, attr):
|
def _get_attr(self, name, tag, attr):
|
||||||
elem = self._tree.find(name).find(tag)
|
elem = self._tree.find(name).find(tag)
|
||||||
if elem is None:
|
if elem is None:
|
||||||
return None
|
return ""
|
||||||
return elem.attrib[attr]
|
return elem.attrib[attr]
|
||||||
|
|
||||||
def _set_attr(self, name, tag, attr, value):
|
def _set_attr(self, name, tag, attr, value):
|
||||||
@ -225,7 +229,7 @@ class AnatricConfig:
|
|||||||
elem = self._tree.find("crystal").find("UB")
|
elem = self._tree.find("crystal").find("UB")
|
||||||
if elem is not None:
|
if elem is not None:
|
||||||
return elem.text
|
return elem.text
|
||||||
return None
|
return ""
|
||||||
|
|
||||||
@crystal_UB.setter
|
@crystal_UB.setter
|
||||||
def crystal_UB(self, value):
|
def crystal_UB(self, value):
|
||||||
@ -247,7 +251,7 @@ class AnatricConfig:
|
|||||||
elem = self._tree.find("DataFactory").find("dist1")
|
elem = self._tree.find("DataFactory").find("dist1")
|
||||||
if elem is not None:
|
if elem is not None:
|
||||||
return elem.attrib["value"]
|
return elem.attrib["value"]
|
||||||
return None
|
return ""
|
||||||
|
|
||||||
@dataFactory_dist1.setter
|
@dataFactory_dist1.setter
|
||||||
def dataFactory_dist1(self, value):
|
def dataFactory_dist1(self, value):
|
||||||
@ -258,7 +262,7 @@ class AnatricConfig:
|
|||||||
elem = self._tree.find("DataFactory").find("dist2")
|
elem = self._tree.find("DataFactory").find("dist2")
|
||||||
if elem is not None:
|
if elem is not None:
|
||||||
return elem.attrib["value"]
|
return elem.attrib["value"]
|
||||||
return None
|
return ""
|
||||||
|
|
||||||
@dataFactory_dist2.setter
|
@dataFactory_dist2.setter
|
||||||
def dataFactory_dist2(self, value):
|
def dataFactory_dist2(self, value):
|
||||||
@ -269,7 +273,7 @@ class AnatricConfig:
|
|||||||
elem = self._tree.find("DataFactory").find("dist3")
|
elem = self._tree.find("DataFactory").find("dist3")
|
||||||
if elem is not None:
|
if elem is not None:
|
||||||
return elem.attrib["value"]
|
return elem.attrib["value"]
|
||||||
return None
|
return ""
|
||||||
|
|
||||||
@dataFactory_dist3.setter
|
@dataFactory_dist3.setter
|
||||||
def dataFactory_dist3(self, value):
|
def dataFactory_dist3(self, value):
|
||||||
@ -310,7 +314,7 @@ class AnatricConfig:
|
|||||||
def _get_alg_attr(self, alg, tag, attr):
|
def _get_alg_attr(self, alg, tag, attr):
|
||||||
param_elem = self._alg_elems[alg].find(tag)
|
param_elem = self._alg_elems[alg].find(tag)
|
||||||
if param_elem is None:
|
if param_elem is None:
|
||||||
return None
|
return ""
|
||||||
return param_elem.attrib[attr]
|
return param_elem.attrib[attr]
|
||||||
|
|
||||||
def _set_alg_attr(self, alg, tag, attr, value):
|
def _set_alg_attr(self, alg, tag, attr, value):
|
||||||
|
@ -47,9 +47,11 @@ from pyzebra.ccl_io import AREA_METHODS
|
|||||||
|
|
||||||
|
|
||||||
javaScript = """
|
javaScript = """
|
||||||
|
let j = 0;
|
||||||
for (let i = 0; i < js_data.data['fname'].length; i++) {
|
for (let i = 0; i < js_data.data['fname'].length; i++) {
|
||||||
if (js_data.data['content'][i] === "") continue;
|
if (js_data.data['content'][i] === "") continue;
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
const blob = new Blob([js_data.data['content'][i]], {type: 'text/plain'})
|
const blob = new Blob([js_data.data['content'][i]], {type: 'text/plain'})
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
@ -59,6 +61,9 @@ for (let i = 0; i < js_data.data['fname'].length; i++) {
|
|||||||
link.click();
|
link.click();
|
||||||
window.URL.revokeObjectURL(url);
|
window.URL.revokeObjectURL(url);
|
||||||
document.body.removeChild(link);
|
document.body.removeChild(link);
|
||||||
|
}, 100 * j)
|
||||||
|
|
||||||
|
j++;
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -72,11 +77,11 @@ def create():
|
|||||||
proposal = new.strip()
|
proposal = new.strip()
|
||||||
year = new[:4]
|
year = new[:4]
|
||||||
proposal_path = f"/afs/psi.ch/project/sinqdata/{year}/zebra/{proposal}"
|
proposal_path = f"/afs/psi.ch/project/sinqdata/{year}/zebra/{proposal}"
|
||||||
ccl_file_list = []
|
file_list = []
|
||||||
for file in os.listdir(proposal_path):
|
for file in os.listdir(proposal_path):
|
||||||
if file.endswith((".ccl", ".dat")):
|
if file.endswith((".ccl", ".dat")):
|
||||||
ccl_file_list.append((os.path.join(proposal_path, file), file))
|
file_list.append((os.path.join(proposal_path, file), file))
|
||||||
file_select.options = ccl_file_list
|
file_select.options = file_list
|
||||||
|
|
||||||
proposal_textinput = TextInput(title="Proposal number:", width=210)
|
proposal_textinput = TextInput(title="Proposal number:", width=210)
|
||||||
proposal_textinput.on_change("value", proposal_textinput_callback)
|
proposal_textinput.on_change("value", proposal_textinput_callback)
|
||||||
@ -97,11 +102,7 @@ def create():
|
|||||||
merge_dest_select.options = merge_options
|
merge_dest_select.options = merge_options
|
||||||
merge_dest_select.value = merge_options[0][0]
|
merge_dest_select.value = merge_options[0][0]
|
||||||
|
|
||||||
def ccl_file_select_callback(_attr, _old, _new):
|
|
||||||
pass
|
|
||||||
|
|
||||||
file_select = MultiSelect(title="Available .ccl/.dat files:", width=210, height=250)
|
file_select = MultiSelect(title="Available .ccl/.dat files:", width=210, height=250)
|
||||||
file_select.on_change("value", ccl_file_select_callback)
|
|
||||||
|
|
||||||
def file_open_button_callback():
|
def file_open_button_callback():
|
||||||
nonlocal det_data
|
nonlocal det_data
|
||||||
@ -120,7 +121,6 @@ def create():
|
|||||||
js_data.data.update(fname=[base + ".comm", base + ".incomm"])
|
js_data.data.update(fname=[base + ".comm", base + ".incomm"])
|
||||||
|
|
||||||
_init_datatable()
|
_init_datatable()
|
||||||
_update_preview()
|
|
||||||
|
|
||||||
file_open_button = Button(label="Open New", width=100)
|
file_open_button = Button(label="Open New", width=100)
|
||||||
file_open_button.on_click(file_open_button_callback)
|
file_open_button.on_click(file_open_button_callback)
|
||||||
@ -156,7 +156,6 @@ def create():
|
|||||||
js_data.data.update(fname=[base + ".comm", base + ".incomm"])
|
js_data.data.update(fname=[base + ".comm", base + ".incomm"])
|
||||||
|
|
||||||
_init_datatable()
|
_init_datatable()
|
||||||
_update_preview()
|
|
||||||
|
|
||||||
upload_div = Div(text="or upload new .ccl/.dat files:", margin=(5, 5, 0, 5))
|
upload_div = Div(text="or upload new .ccl/.dat files:", margin=(5, 5, 0, 5))
|
||||||
upload_button = FileInput(accept=".ccl,.dat", multiple=True, width=200)
|
upload_button = FileInput(accept=".ccl,.dat", multiple=True, width=200)
|
||||||
@ -301,7 +300,12 @@ def create():
|
|||||||
|
|
||||||
_update_plot(det_data[new[0]])
|
_update_plot(det_data[new[0]])
|
||||||
|
|
||||||
|
def scan_table_source_callback(_attr, _old, _new):
|
||||||
|
_update_preview()
|
||||||
|
|
||||||
scan_table_source = ColumnDataSource(dict(scan=[], hkl=[], fit=[], export=[]))
|
scan_table_source = ColumnDataSource(dict(scan=[], hkl=[], fit=[], export=[]))
|
||||||
|
scan_table_source.on_change("data", scan_table_source_callback)
|
||||||
|
|
||||||
scan_table = DataTable(
|
scan_table = DataTable(
|
||||||
source=scan_table_source,
|
source=scan_table_source,
|
||||||
columns=[
|
columns=[
|
||||||
@ -425,8 +429,12 @@ def create():
|
|||||||
)
|
)
|
||||||
|
|
||||||
if function == "linear":
|
if function == "linear":
|
||||||
fitparams["value"] = [0, 0]
|
fitparams["value"] = [0, 1]
|
||||||
fitparams["vary"] = [False, True]
|
fitparams["vary"] = [False, True]
|
||||||
|
fitparams["min"] = [None, 0]
|
||||||
|
|
||||||
|
elif function == "gaussian":
|
||||||
|
fitparams["min"] = [0, None, None]
|
||||||
|
|
||||||
return fitparams
|
return fitparams
|
||||||
|
|
||||||
@ -463,7 +471,6 @@ def create():
|
|||||||
|
|
||||||
_update_plot(_get_selected_scan())
|
_update_plot(_get_selected_scan())
|
||||||
_update_table()
|
_update_table()
|
||||||
_update_preview()
|
|
||||||
|
|
||||||
fit_all_button = Button(label="Fit All", button_type="primary", width=145)
|
fit_all_button = Button(label="Fit All", button_type="primary", width=145)
|
||||||
fit_all_button.on_click(fit_all_button_callback)
|
fit_all_button.on_click(fit_all_button_callback)
|
||||||
@ -476,7 +483,6 @@ def create():
|
|||||||
|
|
||||||
_update_plot(scan)
|
_update_plot(scan)
|
||||||
_update_table()
|
_update_table()
|
||||||
_update_preview()
|
|
||||||
|
|
||||||
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)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import base64
|
import base64
|
||||||
import io
|
import io
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
@ -347,14 +348,14 @@ def create():
|
|||||||
temp_file = temp_dir + "/config.xml"
|
temp_file = temp_dir + "/config.xml"
|
||||||
config.save_as(temp_file)
|
config.save_as(temp_file)
|
||||||
if doc.anatric_path:
|
if doc.anatric_path:
|
||||||
pyzebra.anatric(temp_file, anatric_path=doc.anatric_path)
|
pyzebra.anatric(temp_file, anatric_path=doc.anatric_path, cwd=temp_dir)
|
||||||
else:
|
else:
|
||||||
pyzebra.anatric(temp_file)
|
pyzebra.anatric(temp_file, cwd=temp_dir)
|
||||||
|
|
||||||
with open(config.logfile) as f_log:
|
with open(os.path.join(temp_dir, config.logfile)) as f_log:
|
||||||
output_log.value = f_log.read()
|
output_log.value = f_log.read()
|
||||||
|
|
||||||
with open(config.reflectionPrinter_file) as f_res:
|
with open(os.path.join(temp_dir, config.reflectionPrinter_file)) as f_res:
|
||||||
output_res.value = f_res.read()
|
output_res.value = f_res.read()
|
||||||
|
|
||||||
process_button = Button(label="Process", button_type="primary")
|
process_button = Button(label="Process", button_type="primary")
|
||||||
@ -389,11 +390,7 @@ def create():
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def update_config():
|
async def update_config():
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
output_config.value = config.tostring()
|
||||||
temp_file = temp_dir + "/config.xml"
|
|
||||||
config.save_as(temp_file)
|
|
||||||
with open(temp_file) as f_config:
|
|
||||||
output_config.value = f_config.read()
|
|
||||||
|
|
||||||
doc.add_periodic_callback(update_config, 1000)
|
doc.add_periodic_callback(update_config, 1000)
|
||||||
|
|
||||||
|
@ -12,9 +12,12 @@ from bokeh.models import (
|
|||||||
CheckboxGroup,
|
CheckboxGroup,
|
||||||
ColumnDataSource,
|
ColumnDataSource,
|
||||||
DataRange1d,
|
DataRange1d,
|
||||||
|
DataTable,
|
||||||
Div,
|
Div,
|
||||||
FileInput,
|
FileInput,
|
||||||
Grid,
|
Grid,
|
||||||
|
MultiSelect,
|
||||||
|
NumberFormatter,
|
||||||
HoverTool,
|
HoverTool,
|
||||||
Image,
|
Image,
|
||||||
Line,
|
Line,
|
||||||
@ -27,8 +30,10 @@ from bokeh.models import (
|
|||||||
Rect,
|
Rect,
|
||||||
ResetTool,
|
ResetTool,
|
||||||
Select,
|
Select,
|
||||||
|
Slider,
|
||||||
Spacer,
|
Spacer,
|
||||||
Spinner,
|
Spinner,
|
||||||
|
TableColumn,
|
||||||
TextAreaInput,
|
TextAreaInput,
|
||||||
TextInput,
|
TextInput,
|
||||||
Title,
|
Title,
|
||||||
@ -40,8 +45,8 @@ import pyzebra
|
|||||||
|
|
||||||
IMAGE_W = 256
|
IMAGE_W = 256
|
||||||
IMAGE_H = 128
|
IMAGE_H = 128
|
||||||
IMAGE_PLOT_W = int(IMAGE_W * 2.5)
|
IMAGE_PLOT_W = int(IMAGE_W * 2) + 52
|
||||||
IMAGE_PLOT_H = int(IMAGE_H * 2.5)
|
IMAGE_PLOT_H = int(IMAGE_H * 2) + 27
|
||||||
|
|
||||||
|
|
||||||
def create():
|
def create():
|
||||||
@ -56,21 +61,19 @@ def create():
|
|||||||
for file in os.listdir(proposal_path):
|
for file in os.listdir(proposal_path):
|
||||||
if file.endswith(".hdf"):
|
if file.endswith(".hdf"):
|
||||||
file_list.append((os.path.join(proposal_path, file), file))
|
file_list.append((os.path.join(proposal_path, file), file))
|
||||||
filelist.options = file_list
|
file_select.options = file_list
|
||||||
filelist.value = file_list[0][0]
|
|
||||||
|
|
||||||
proposal_textinput = TextInput(title="Enter proposal number:", width=145)
|
proposal_textinput = TextInput(title="Proposal number:", width=210)
|
||||||
proposal_textinput.on_change("value", proposal_textinput_callback)
|
proposal_textinput.on_change("value", proposal_textinput_callback)
|
||||||
|
|
||||||
def upload_button_callback(_attr, _old, new):
|
def upload_button_callback(_attr, _old, new):
|
||||||
with io.StringIO(base64.b64decode(new).decode()) as file:
|
with io.StringIO(base64.b64decode(new).decode()) as file:
|
||||||
h5meta_list = pyzebra.parse_h5meta(file)
|
h5meta_list = pyzebra.parse_h5meta(file)
|
||||||
file_list = h5meta_list["filelist"]
|
file_list = h5meta_list["filelist"]
|
||||||
filelist.options = [(entry, os.path.basename(entry)) for entry in file_list]
|
file_select.options = [(entry, os.path.basename(entry)) for entry in file_list]
|
||||||
filelist.value = file_list[0]
|
|
||||||
|
|
||||||
upload_div = Div(text="or upload .cami file:", margin=(5, 5, 0, 5))
|
upload_div = Div(text="or upload .cami file:", margin=(5, 5, 0, 5))
|
||||||
upload_button = FileInput(accept=".cami")
|
upload_button = FileInput(accept=".cami", width=200)
|
||||||
upload_button.on_change("value", upload_button_callback)
|
upload_button.on_change("value", upload_button_callback)
|
||||||
|
|
||||||
def update_image(index=None):
|
def update_image(index=None):
|
||||||
@ -101,14 +104,14 @@ def create():
|
|||||||
image_glyph.color_mapper.high = im_max
|
image_glyph.color_mapper.high = im_max
|
||||||
|
|
||||||
if "mf" in det_data:
|
if "mf" in det_data:
|
||||||
mf_spinner.value = det_data["mf"][index]
|
metadata_table_source.data.update(mf=[det_data["mf"][index]])
|
||||||
else:
|
else:
|
||||||
mf_spinner.value = None
|
metadata_table_source.data.update(mf=[None])
|
||||||
|
|
||||||
if "temp" in det_data:
|
if "temp" in det_data:
|
||||||
temp_spinner.value = det_data["temp"][index]
|
metadata_table_source.data.update(temp=[det_data["temp"][index]])
|
||||||
else:
|
else:
|
||||||
temp_spinner.value = None
|
metadata_table_source.data.update(temp=[None])
|
||||||
|
|
||||||
gamma, nu = calculate_pol(det_data, index)
|
gamma, nu = calculate_pol(det_data, index)
|
||||||
omega = np.ones((IMAGE_H, IMAGE_W)) * det_data["omega"][index]
|
omega = np.ones((IMAGE_H, IMAGE_W)) * det_data["omega"][index]
|
||||||
@ -154,30 +157,50 @@ def create():
|
|||||||
scanning_motor_range.reset_end = var_end
|
scanning_motor_range.reset_end = var_end
|
||||||
scanning_motor_range.bounds = (var_start, var_end)
|
scanning_motor_range.bounds = (var_start, var_end)
|
||||||
|
|
||||||
def filelist_callback(_attr, _old, new):
|
def file_select_callback(_attr, old, new):
|
||||||
nonlocal det_data
|
nonlocal det_data
|
||||||
det_data = pyzebra.read_detector_data(new)
|
if not new:
|
||||||
|
# skip empty selections
|
||||||
|
return
|
||||||
|
|
||||||
|
# Avoid selection of multiple indicies (via Shift+Click or Ctrl+Click)
|
||||||
|
if len(new) > 1:
|
||||||
|
# drop selection to the previous one
|
||||||
|
file_select.value = old
|
||||||
|
return
|
||||||
|
|
||||||
|
if len(old) > 1:
|
||||||
|
# skip unnecessary update caused by selection drop
|
||||||
|
return
|
||||||
|
|
||||||
|
det_data = pyzebra.read_detector_data(new[0])
|
||||||
|
|
||||||
index_spinner.value = 0
|
index_spinner.value = 0
|
||||||
index_spinner.high = det_data["data"].shape[0] - 1
|
index_spinner.high = det_data["data"].shape[0] - 1
|
||||||
|
index_slider.end = det_data["data"].shape[0] - 1
|
||||||
|
|
||||||
zebra_mode = det_data["zebra_mode"]
|
zebra_mode = det_data["zebra_mode"]
|
||||||
if zebra_mode == "nb":
|
if zebra_mode == "nb":
|
||||||
geometry_textinput.value = "normal beam"
|
metadata_table_source.data.update(geom=["normal beam"])
|
||||||
else: # zebra_mode == "bi"
|
else: # zebra_mode == "bi"
|
||||||
geometry_textinput.value = "bisecting"
|
metadata_table_source.data.update(geom=["bisecting"])
|
||||||
|
|
||||||
update_image(0)
|
update_image(0)
|
||||||
update_overview_plot()
|
update_overview_plot()
|
||||||
|
|
||||||
filelist = Select(title="Available .hdf files:")
|
file_select = MultiSelect(title="Available .hdf files:", width=210, height=250)
|
||||||
filelist.on_change("value", filelist_callback)
|
file_select.on_change("value", file_select_callback)
|
||||||
|
|
||||||
def index_spinner_callback(_attr, _old, new):
|
def index_callback(_attr, _old, new):
|
||||||
update_image(new)
|
update_image(new)
|
||||||
|
|
||||||
index_spinner = Spinner(title="Image index:", value=0, low=0, width=80)
|
index_slider = Slider(value=0, start=0, end=1, show_value=False, width=400)
|
||||||
index_spinner.on_change("value", index_spinner_callback)
|
|
||||||
|
index_spinner = Spinner(title="Image index:", value=0, low=0, width=100)
|
||||||
|
index_spinner.on_change("value", index_callback)
|
||||||
|
|
||||||
|
index_slider.js_link("value_throttled", index_spinner, "value")
|
||||||
|
index_spinner.js_link("value", index_slider, "value")
|
||||||
|
|
||||||
plot = Plot(
|
plot = Plot(
|
||||||
x_range=Range1d(0, IMAGE_W, bounds=(0, IMAGE_W)),
|
x_range=Range1d(0, IMAGE_W, bounds=(0, IMAGE_W)),
|
||||||
@ -321,7 +344,7 @@ def create():
|
|||||||
y_range=frame_range,
|
y_range=frame_range,
|
||||||
extra_y_ranges={"scanning_motor": scanning_motor_range},
|
extra_y_ranges={"scanning_motor": scanning_motor_range},
|
||||||
plot_height=400,
|
plot_height=400,
|
||||||
plot_width=IMAGE_PLOT_W,
|
plot_width=IMAGE_PLOT_W - 3,
|
||||||
)
|
)
|
||||||
|
|
||||||
# ---- tools
|
# ---- tools
|
||||||
@ -359,7 +382,7 @@ def create():
|
|||||||
y_range=frame_range,
|
y_range=frame_range,
|
||||||
extra_y_ranges={"scanning_motor": scanning_motor_range},
|
extra_y_ranges={"scanning_motor": scanning_motor_range},
|
||||||
plot_height=400,
|
plot_height=400,
|
||||||
plot_width=IMAGE_PLOT_H,
|
plot_width=IMAGE_PLOT_H + 22,
|
||||||
)
|
)
|
||||||
|
|
||||||
# ---- tools
|
# ---- tools
|
||||||
@ -398,7 +421,7 @@ def create():
|
|||||||
roi_avg_plot = Plot(
|
roi_avg_plot = Plot(
|
||||||
x_range=DataRange1d(),
|
x_range=DataRange1d(),
|
||||||
y_range=DataRange1d(),
|
y_range=DataRange1d(),
|
||||||
plot_height=200,
|
plot_height=150,
|
||||||
plot_width=IMAGE_PLOT_W,
|
plot_width=IMAGE_PLOT_W,
|
||||||
toolbar_location="left",
|
toolbar_location="left",
|
||||||
)
|
)
|
||||||
@ -548,7 +571,7 @@ def create():
|
|||||||
int(np.ceil(frame_range.end)),
|
int(np.ceil(frame_range.end)),
|
||||||
]
|
]
|
||||||
|
|
||||||
filename_id = filelist.value[-8:-4]
|
filename_id = file_select.value[0][-8:-4]
|
||||||
if filename_id in roi_selection:
|
if filename_id in roi_selection:
|
||||||
roi_selection[f"{filename_id}"].append(selection)
|
roi_selection[f"{filename_id}"].append(selection)
|
||||||
else:
|
else:
|
||||||
@ -559,11 +582,23 @@ def create():
|
|||||||
selection_button = Button(label="Add selection")
|
selection_button = Button(label="Add selection")
|
||||||
selection_button.on_click(selection_button_callback)
|
selection_button.on_click(selection_button_callback)
|
||||||
|
|
||||||
mf_spinner = Spinner(title="Magnetic field:", format="0.00", width=100, disabled=True)
|
metadata_table_source = ColumnDataSource(dict(geom=[""], temp=[None], mf=[None]))
|
||||||
temp_spinner = Spinner(title="Temperature:", format="0.00", width=100, disabled=True)
|
num_formatter = NumberFormatter(format="0.00", nan_format="")
|
||||||
geometry_textinput = TextInput(title="Geometry:", width=120, disabled=True)
|
metadata_table = DataTable(
|
||||||
|
source=metadata_table_source,
|
||||||
|
columns=[
|
||||||
|
TableColumn(field="geom", title="Geometry", width=100),
|
||||||
|
TableColumn(field="temp", title="Temperature", formatter=num_formatter, width=100),
|
||||||
|
TableColumn(field="mf", title="Magnetic Field", formatter=num_formatter, width=100),
|
||||||
|
],
|
||||||
|
width=300,
|
||||||
|
height=50,
|
||||||
|
autosize_mode="none",
|
||||||
|
index_position=None,
|
||||||
|
)
|
||||||
|
|
||||||
# Final layout
|
# Final layout
|
||||||
|
import_layout = column(proposal_textinput, upload_div, upload_button, file_select)
|
||||||
layout_image = column(gridplot([[proj_v, None], [plot, proj_h]], merge_tools=False))
|
layout_image = column(gridplot([[proj_v, None], [plot, proj_h]], merge_tools=False))
|
||||||
colormap_layout = column(
|
colormap_layout = column(
|
||||||
colormap,
|
colormap,
|
||||||
@ -576,9 +611,9 @@ def create():
|
|||||||
layout_controls = row(
|
layout_controls = row(
|
||||||
column(selection_button, selection_list),
|
column(selection_button, selection_list),
|
||||||
Spacer(width=20),
|
Spacer(width=20),
|
||||||
column(colormap_layout),
|
column(
|
||||||
Spacer(width=20),
|
row(index_spinner, column(Spacer(height=25), index_slider)), metadata_table, hkl_button
|
||||||
column(row(mf_spinner, temp_spinner), row(geometry_textinput, index_spinner), hkl_button),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
layout_overview = column(
|
layout_overview = column(
|
||||||
@ -591,13 +626,8 @@ def create():
|
|||||||
)
|
)
|
||||||
|
|
||||||
tab_layout = row(
|
tab_layout = row(
|
||||||
column(
|
column(import_layout, colormap_layout),
|
||||||
row(
|
column(layout_overview, layout_controls),
|
||||||
proposal_textinput, filelist, Spacer(width=100), column(upload_div, upload_button),
|
|
||||||
),
|
|
||||||
layout_overview,
|
|
||||||
layout_controls,
|
|
||||||
),
|
|
||||||
column(roi_avg_plot, layout_image),
|
column(roi_avg_plot, layout_image),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -81,11 +81,11 @@ def create():
|
|||||||
proposal = new.strip()
|
proposal = new.strip()
|
||||||
year = new[:4]
|
year = new[:4]
|
||||||
proposal_path = f"/afs/psi.ch/project/sinqdata/{year}/zebra/{proposal}"
|
proposal_path = f"/afs/psi.ch/project/sinqdata/{year}/zebra/{proposal}"
|
||||||
dat_file_list = []
|
file_list = []
|
||||||
for file in os.listdir(proposal_path):
|
for file in os.listdir(proposal_path):
|
||||||
if file.endswith(".dat"):
|
if file.endswith((".ccl", ".dat")):
|
||||||
dat_file_list.append((os.path.join(proposal_path, file), file))
|
file_list.append((os.path.join(proposal_path, file), file))
|
||||||
file_select.options = dat_file_list
|
file_select.options = file_list
|
||||||
|
|
||||||
proposal_textinput = TextInput(title="Proposal number:", width=210)
|
proposal_textinput = TextInput(title="Proposal number:", width=210)
|
||||||
proposal_textinput.on_change("value", proposal_textinput_callback)
|
proposal_textinput.on_change("value", proposal_textinput_callback)
|
||||||
@ -108,11 +108,7 @@ def create():
|
|||||||
|
|
||||||
param_select.value = "user defined"
|
param_select.value = "user defined"
|
||||||
|
|
||||||
def file_select_callback(_attr, _old, _new):
|
file_select = MultiSelect(title="Available .ccl/.dat files:", width=210, height=250)
|
||||||
pass
|
|
||||||
|
|
||||||
file_select = MultiSelect(title="Available .dat files:", width=210, height=250)
|
|
||||||
file_select.on_change("value", file_select_callback)
|
|
||||||
|
|
||||||
def file_open_button_callback():
|
def file_open_button_callback():
|
||||||
nonlocal det_data
|
nonlocal det_data
|
||||||
@ -130,7 +126,6 @@ def create():
|
|||||||
js_data.data.update(fname=[base + ".comm", base + ".incomm"])
|
js_data.data.update(fname=[base + ".comm", base + ".incomm"])
|
||||||
|
|
||||||
_init_datatable()
|
_init_datatable()
|
||||||
_update_preview()
|
|
||||||
|
|
||||||
file_open_button = Button(label="Open New", width=100)
|
file_open_button = Button(label="Open New", width=100)
|
||||||
file_open_button.on_click(file_open_button_callback)
|
file_open_button.on_click(file_open_button_callback)
|
||||||
@ -165,10 +160,9 @@ def create():
|
|||||||
js_data.data.update(fname=[base + ".comm", base + ".incomm"])
|
js_data.data.update(fname=[base + ".comm", base + ".incomm"])
|
||||||
|
|
||||||
_init_datatable()
|
_init_datatable()
|
||||||
_update_preview()
|
|
||||||
|
|
||||||
upload_div = Div(text="or upload new .dat files:", margin=(5, 5, 0, 5))
|
upload_div = Div(text="or upload new .ccl/.dat files:", margin=(5, 5, 0, 5))
|
||||||
upload_button = FileInput(accept=".dat", multiple=True, width=200)
|
upload_button = FileInput(accept=".ccl,.dat", multiple=True, width=200)
|
||||||
upload_button.on_change("value", upload_button_callback)
|
upload_button.on_change("value", upload_button_callback)
|
||||||
|
|
||||||
def append_upload_button_callback(_attr, _old, new):
|
def append_upload_button_callback(_attr, _old, new):
|
||||||
@ -183,7 +177,7 @@ def create():
|
|||||||
_init_datatable()
|
_init_datatable()
|
||||||
|
|
||||||
append_upload_div = Div(text="append extra files:", margin=(5, 5, 0, 5))
|
append_upload_div = Div(text="append extra files:", margin=(5, 5, 0, 5))
|
||||||
append_upload_button = FileInput(accept=".dat", multiple=True, width=200)
|
append_upload_button = FileInput(accept=".ccl,.dat", multiple=True, width=200)
|
||||||
append_upload_button.on_change("value", append_upload_button_callback)
|
append_upload_button.on_change("value", append_upload_button_callback)
|
||||||
|
|
||||||
def monitor_spinner_callback(_attr, _old, new):
|
def monitor_spinner_callback(_attr, _old, new):
|
||||||
@ -392,7 +386,12 @@ def create():
|
|||||||
|
|
||||||
_update_plot()
|
_update_plot()
|
||||||
|
|
||||||
|
def scan_table_source_callback(_attr, _old, _new):
|
||||||
|
_update_preview()
|
||||||
|
|
||||||
scan_table_source = ColumnDataSource(dict(file=[], scan=[], param=[], fit=[], export=[]))
|
scan_table_source = ColumnDataSource(dict(file=[], scan=[], param=[], fit=[], export=[]))
|
||||||
|
scan_table_source.on_change("data", scan_table_source_callback)
|
||||||
|
|
||||||
scan_table = DataTable(
|
scan_table = DataTable(
|
||||||
source=scan_table_source,
|
source=scan_table_source,
|
||||||
columns=[
|
columns=[
|
||||||
@ -519,8 +518,12 @@ def create():
|
|||||||
)
|
)
|
||||||
|
|
||||||
if function == "linear":
|
if function == "linear":
|
||||||
fitparams["value"] = [0, 0]
|
fitparams["value"] = [0, 1]
|
||||||
fitparams["vary"] = [False, True]
|
fitparams["vary"] = [False, True]
|
||||||
|
fitparams["min"] = [None, 0]
|
||||||
|
|
||||||
|
elif function == "gaussian":
|
||||||
|
fitparams["min"] = [0, None, None]
|
||||||
|
|
||||||
return fitparams
|
return fitparams
|
||||||
|
|
||||||
@ -557,7 +560,6 @@ def create():
|
|||||||
|
|
||||||
_update_plot()
|
_update_plot()
|
||||||
_update_table()
|
_update_table()
|
||||||
_update_preview()
|
|
||||||
|
|
||||||
fit_all_button = Button(label="Fit All", button_type="primary", width=145)
|
fit_all_button = Button(label="Fit All", button_type="primary", width=145)
|
||||||
fit_all_button.on_click(fit_all_button_callback)
|
fit_all_button.on_click(fit_all_button_callback)
|
||||||
@ -570,7 +572,6 @@ def create():
|
|||||||
|
|
||||||
_update_plot()
|
_update_plot()
|
||||||
_update_table()
|
_update_table()
|
||||||
_update_preview()
|
|
||||||
|
|
||||||
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)
|
||||||
|
@ -3,7 +3,6 @@ import math
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from bokeh.layouts import column, row
|
from bokeh.layouts import column, row
|
||||||
@ -38,6 +37,9 @@ def create():
|
|||||||
ub_matrices = []
|
ub_matrices = []
|
||||||
|
|
||||||
def process_button_callback():
|
def process_button_callback():
|
||||||
|
# drop table selection to clear result fields
|
||||||
|
results_table_source.selected.indices = []
|
||||||
|
|
||||||
nonlocal diff_vec
|
nonlocal diff_vec
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
temp_peak_list_dir = os.path.join(temp_dir, "peak_list")
|
temp_peak_list_dir = os.path.join(temp_dir, "peak_list")
|
||||||
@ -52,7 +54,7 @@ def create():
|
|||||||
"-n",
|
"-n",
|
||||||
"2",
|
"2",
|
||||||
"python",
|
"python",
|
||||||
"spind/gen_hkl_table.py",
|
os.path.expanduser("~/spind/gen_hkl_table.py"),
|
||||||
lattice_const_textinput.value,
|
lattice_const_textinput.value,
|
||||||
"--max-res",
|
"--max-res",
|
||||||
str(max_res_spinner.value),
|
str(max_res_spinner.value),
|
||||||
@ -79,7 +81,7 @@ def create():
|
|||||||
"-n",
|
"-n",
|
||||||
"2",
|
"2",
|
||||||
"python",
|
"python",
|
||||||
"spind/SPIND.py",
|
os.path.expanduser("~/spind/SPIND.py"),
|
||||||
temp_peak_list_dir,
|
temp_peak_list_dir,
|
||||||
temp_hkl_file,
|
temp_hkl_file,
|
||||||
"-o",
|
"-o",
|
||||||
@ -102,9 +104,11 @@ def create():
|
|||||||
print(comp_proc.stdout)
|
print(comp_proc.stdout)
|
||||||
|
|
||||||
spind_out_file = os.path.join(temp_dir, "spind.txt")
|
spind_out_file = os.path.join(temp_dir, "spind.txt")
|
||||||
|
spind_res = dict(
|
||||||
|
label=[], crystal_id=[], match_rate=[], matched_peaks=[], column_5=[], ub_matrix=[],
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
with open(spind_out_file) as f_out:
|
with open(spind_out_file) as f_out:
|
||||||
spind_res = defaultdict(list)
|
|
||||||
for line in f_out:
|
for line in f_out:
|
||||||
c1, c2, c3, c4, c5, *c_rest = line.split()
|
c1, c2, c3, c4, c5, *c_rest = line.split()
|
||||||
spind_res["label"].append(c1)
|
spind_res["label"].append(c1)
|
||||||
@ -115,12 +119,10 @@ def create():
|
|||||||
|
|
||||||
# last digits are spind UB matrix
|
# last digits are spind UB matrix
|
||||||
vals = list(map(float, c_rest))
|
vals = list(map(float, c_rest))
|
||||||
ub_matrix_spind = np.array(vals).reshape(3, 3)
|
ub_matrix_spind = np.transpose(np.array(vals).reshape(3, 3))
|
||||||
ub_matrix = np.linalg.inv(np.transpose(ub_matrix_spind))
|
ub_matrix = np.linalg.inv(ub_matrix_spind)
|
||||||
ub_matrices.append(ub_matrix)
|
ub_matrices.append(ub_matrix)
|
||||||
spind_res["ub_matrix"].append(ub_matrix_spind)
|
spind_res["ub_matrix"].append(str(ub_matrix_spind * 1e-10))
|
||||||
|
|
||||||
results_table_source.data.update(spind_res)
|
|
||||||
|
|
||||||
print(f"Content of {spind_out_file}:")
|
print(f"Content of {spind_out_file}:")
|
||||||
with open(spind_out_file) as f:
|
with open(spind_out_file) as f:
|
||||||
@ -129,6 +131,8 @@ def create():
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print("No results from spind")
|
print("No results from spind")
|
||||||
|
|
||||||
|
results_table_source.data.update(spind_res)
|
||||||
|
|
||||||
process_button = Button(label="Process", button_type="primary")
|
process_button = Button(label="Process", button_type="primary")
|
||||||
process_button.on_click(process_button_callback)
|
process_button.on_click(process_button_callback)
|
||||||
|
|
||||||
@ -145,10 +149,12 @@ def create():
|
|||||||
ub_matrix_textareainput.value = str(ub_matrix * 1e10)
|
ub_matrix_textareainput.value = str(ub_matrix * 1e10)
|
||||||
hkl_textareainput.value = res
|
hkl_textareainput.value = res
|
||||||
else:
|
else:
|
||||||
ub_matrix_textareainput.value = None
|
ub_matrix_textareainput.value = ""
|
||||||
hkl_textareainput.value = None
|
hkl_textareainput.value = ""
|
||||||
|
|
||||||
results_table_source = ColumnDataSource(dict())
|
results_table_source = ColumnDataSource(
|
||||||
|
dict(label=[], crystal_id=[], match_rate=[], matched_peaks=[], column_5=[], ub_matrix=[])
|
||||||
|
)
|
||||||
results_table = DataTable(
|
results_table = DataTable(
|
||||||
source=results_table_source,
|
source=results_table_source,
|
||||||
columns=[
|
columns=[
|
||||||
|
@ -261,22 +261,24 @@ def export_1D(data, path, area_method=AREA_METHODS[0], lorentz=False, hkl_precis
|
|||||||
h, k, l = scan["h"], scan["k"], scan["l"]
|
h, k, l = scan["h"], scan["k"], scan["l"]
|
||||||
hkl_are_integers = isinstance(h, int) # if True, other indices are of type 'int' too
|
hkl_are_integers = isinstance(h, int) # if True, other indices are of type 'int' too
|
||||||
if hkl_are_integers:
|
if hkl_are_integers:
|
||||||
hkl_str = f"{h:6}{k:6}{l:6}"
|
hkl_str = f"{h:4}{k:4}{l:4}"
|
||||||
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():
|
for name, param in scan["fit"].params.items():
|
||||||
if "amplitude" in name:
|
if "amplitude" in name:
|
||||||
|
if param.stderr is None:
|
||||||
|
area_n = np.nan
|
||||||
|
area_s = np.nan
|
||||||
|
else:
|
||||||
area_n = param.value
|
area_n = param.value
|
||||||
area_s = param.stderr
|
area_s = param.stderr
|
||||||
|
# TODO: take into account multiple peaks
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
area_n = 0
|
# no peak functions in a fit model
|
||||||
area_s = 0
|
area_n = np.nan
|
||||||
|
area_s = np.nan
|
||||||
if area_n is None or area_s is None:
|
|
||||||
print(f"Couldn't export scan: {scan['idx']}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# apply lorentz correction to area
|
# apply lorentz correction to area
|
||||||
if lorentz:
|
if lorentz:
|
||||||
|
@ -128,6 +128,17 @@ def fit_scan(scan, model_dict, fit_from=None, fit_to=None):
|
|||||||
else:
|
else:
|
||||||
param_hints[hint_name] = tmp
|
param_hints[hint_name] = tmp
|
||||||
|
|
||||||
|
if "center" in param_name:
|
||||||
|
if np.isneginf(param_hints["min"]):
|
||||||
|
param_hints["min"] = np.min(x_fit)
|
||||||
|
|
||||||
|
if np.isposinf(param_hints["max"]):
|
||||||
|
param_hints["max"] = np.max(x_fit)
|
||||||
|
|
||||||
|
if "sigma" in param_name:
|
||||||
|
if np.isposinf(param_hints["max"]):
|
||||||
|
param_hints["max"] = np.max(x_fit) - np.min(x_fit)
|
||||||
|
|
||||||
_model.set_param_hint(param_name, **param_hints)
|
_model.set_param_hint(param_name, **param_hints)
|
||||||
|
|
||||||
if model is None:
|
if model is None:
|
||||||
|
Reference in New Issue
Block a user