630 lines
23 KiB
Python
630 lines
23 KiB
Python
# This script contains seveal user functions:
|
|
# 1 bml_save_current_settings()
|
|
# 2 bml_current_settings_for_functions()
|
|
# 3 bml_display_current_settings()
|
|
# 4 bml_restore_saved_settings()
|
|
# 5 bml_display_saved_settings()
|
|
# 6 bml_show_difference_to_saved_settings()
|
|
|
|
# A bit more in detail:
|
|
# 1 bml_save_current_settings()
|
|
# 2 save_data_and_config(default_dir=DATA_DIR, default_name=None):
|
|
# 3 select_components(selected_components=None) - is called by the following functions)
|
|
# 4 bml_display_current_settings(selected_components=None)
|
|
# 5 bml_restore_saved_settings(selected_components=None)
|
|
# 6 bml_display_saved_settings(selected_components=None)
|
|
# 7 bml_show_difference_to_saved_settings(selected_components=None)
|
|
# see also Python Projekte/Strings in Datei speichern
|
|
|
|
from collections import OrderedDict
|
|
import os
|
|
import json
|
|
import shutil
|
|
|
|
from javax.swing import JFrame, JFileChooser
|
|
from javax.swing.filechooser import FileNameExtensionFilter
|
|
from java.io import File
|
|
|
|
BEAMLINE_PARAMETERS_FILE = "/home/gac-x11ma/pshell/home/script/beamline_alignment/bml_align_params.json"
|
|
DATA_FILE = "/home/gac-x11ma/pshell/home/data/2025_11/20251113/Monocam_AU_131.json"
|
|
DATA_DIR = "/home/gac-x11ma/network_drives/home/Data/2025_11/"
|
|
|
|
#DATA_FILE = "/sls/X11MA/data/X11MA/scans/2511/0081.json"
|
|
#DATA_FILE = "/home/gac-x11ma/pshell/home/data/2025_11/20251113/Monocam_AU_131.json"
|
|
#DATA_DIR = "/home/gac-x11ma/pshell/home/data/2025_11/"
|
|
|
|
def save_data_and_config(default_dir=DATA_DIR, default_name=None, save_dialog=True):
|
|
"""
|
|
Offnet einen JSON-Datei-Dialog.
|
|
|
|
Parameter:
|
|
default_dir (str): Optionaler Standardordner
|
|
default_name (str): Optionaler Standard-Dateiname (nur relevant beim Speichern)
|
|
save_dialog (bool): True = "Speichern unter", False = "Offnen"
|
|
|
|
Ruckgabe:
|
|
tuple (full_path, name_without_ext) oder (None, None), falls abgebrochen
|
|
"""
|
|
frame = JFrame()
|
|
frame.setAlwaysOnTop(True)
|
|
|
|
chooser = JFileChooser()
|
|
|
|
# Default-Ordner setzen
|
|
if default_dir:
|
|
chooser.setCurrentDirectory(File(default_dir))
|
|
|
|
# Default-Dateiname nur beim Speichern
|
|
if save_dialog and default_dir and default_name:
|
|
chooser.setSelectedFile(File(default_dir, default_name))
|
|
|
|
# JSON-Filter
|
|
json_filter = FileNameExtensionFilter("JSON Dateien (*.json)", ["json"])
|
|
chooser.setFileFilter(json_filter)
|
|
|
|
# Dialog anzeigen
|
|
if save_dialog:
|
|
result = chooser.showSaveDialog(frame)
|
|
else:
|
|
result = chooser.showOpenDialog(frame)
|
|
|
|
if result == JFileChooser.APPROVE_OPTION:
|
|
file = chooser.getSelectedFile()
|
|
path = file.getAbsolutePath()
|
|
|
|
# Nur beim Speichern: sicherstellen, dass .json angehangt wird
|
|
if save_dialog and not path.lower().endswith(".json"):
|
|
path += ".json"
|
|
|
|
name_without_ext = os.path.splitext(os.path.basename(path))[0]
|
|
return path, name_without_ext
|
|
else:
|
|
return None, None
|
|
|
|
|
|
def bml_save_current_settings():
|
|
# Allows the user to save relevant beamline parameters in aJSON file.
|
|
|
|
path, name_only = save_data_and_config(default_dir=DATA_DIR, default_name=None, save_dialog=True)
|
|
|
|
# 1 Check if the user cancelled
|
|
if path is None:
|
|
print("Aborted by user.")
|
|
return # exit the function immediately
|
|
|
|
# 2 Get the parent folder of the file
|
|
folder = os.path.dirname(path)
|
|
#print(folder)
|
|
# 3 Check if the folder exists
|
|
if not os.path.isdir(folder):
|
|
print("Aborted. Folder: " + folder + " does not exist.")
|
|
return # exit the function cleanly
|
|
|
|
# 4 Mapping from component + parameter to individual read string (Dictionary)
|
|
# Each component contains its parameters, with the corresponding read string
|
|
# and optional tolerance
|
|
with open(BEAMLINE_PARAMETERS_FILE, "r") as f:
|
|
machine_parameters = json.load(f, object_pairs_hook=OrderedDict)
|
|
|
|
parameters = {}
|
|
nan_occurred = False
|
|
|
|
# 5 read each parameter from the machoine
|
|
for comp, param_dict in machine_parameters.items():
|
|
print("\nComponent: " + comp)
|
|
parameters[comp] = {}
|
|
for p, info in param_dict.items():
|
|
cmd = info["read_cmd"]
|
|
# print(cmd)
|
|
tol = info["tolerance"]
|
|
# print(tol)
|
|
try:
|
|
value = caget(cmd)
|
|
if isinstance(value, str):
|
|
display_value = value
|
|
else:
|
|
# value = string(value) c ensure float
|
|
display_value = str(value)
|
|
print(comp + "_" + p + " = " + display_value)
|
|
# print(value)
|
|
except:
|
|
# print("Problem")
|
|
# value = float('nan')
|
|
nan_occurred = True
|
|
print(comp + p + " = NaN")
|
|
parameters[comp][p] = {"value": value, "tolerance": tol}
|
|
|
|
# 6 Save parameters to JSON file
|
|
try:
|
|
with open(path, "w") as f:
|
|
json.dump(parameters, f, indent=4, allow_nan=True)
|
|
print("Parameters successfully saved in: " + path)
|
|
except:
|
|
print("Error while saving file.")
|
|
|
|
# Warn if NaN occurred
|
|
if nan_occurred:
|
|
print("There were NaN-Values")
|
|
|
|
return path, name_only
|
|
|
|
|
|
def bml_save_scan_settings_json(path):
|
|
|
|
# 1 Mapping from component + parameter to individual read string (Dictionary)
|
|
# Each component contains its parameters, with the corresponding read string
|
|
# and optional tolerance
|
|
|
|
with open(BEAMLINE_PARAMETERS_FILE, "r") as f:
|
|
machine_parameters = json.load(f, object_pairs_hook=OrderedDict)
|
|
|
|
parameters = {}
|
|
nan_occurred = False
|
|
|
|
# 2 read each parameter from the machoine
|
|
for comp, param_dict in machine_parameters.items():
|
|
print("\nComponent: " + comp)
|
|
parameters[comp] = {}
|
|
for p, info in param_dict.items():
|
|
cmd = info["read_cmd"]
|
|
# print(cmd)
|
|
tol = info["tolerance"]
|
|
# print(tol)
|
|
try:
|
|
value = caget(cmd)
|
|
if isinstance(value, str):
|
|
display_value = value
|
|
else:
|
|
# value = string(value) c ensure float
|
|
display_value = str(value)
|
|
print(comp + "_" + p + " = " + display_value)
|
|
# print(value)
|
|
except:
|
|
# print("Problem")
|
|
# value = float('nan')
|
|
nan_occurred = True
|
|
print(comp + p + " = NaN")
|
|
parameters[comp][p] = {"value": value, "tolerance": tol}
|
|
|
|
# 3 Save parameters to JSON file
|
|
|
|
file_path = path + "/bml_settings_after_scan.json"
|
|
|
|
try:
|
|
with open(file_path, "w") as f:
|
|
json.dump(parameters, f, indent=4, allow_nan=True)
|
|
print("Parameters successfully saved in: " + file_path)
|
|
except:
|
|
print("Error while saving file.")
|
|
|
|
# Warn if NaN occurred
|
|
if nan_occurred:
|
|
print("There were NaN-Values")
|
|
|
|
|
|
def bml_current_settings_for_functions():
|
|
|
|
# 4 Mapping from component + parameter to individual read string (Dictionary)
|
|
# Each component contains its parameters, with the corresponding read string
|
|
# and optional tolerance
|
|
with open(BEAMLINE_PARAMETERS_FILE, "r") as f:
|
|
machine_parameters = json.load(f, object_pairs_hook=OrderedDict)
|
|
|
|
parameters = {}
|
|
nan_occurred = False
|
|
|
|
# 5 read each parameter from the machoine
|
|
for comp, param_dict in machine_parameters.items():
|
|
print("\nComponent: " + comp)
|
|
parameters[comp] = {}
|
|
for p, info in param_dict.items():
|
|
cmd = info["read_cmd"]
|
|
# print(cmd)
|
|
tol = info["tolerance"]
|
|
# print(tol)
|
|
try:
|
|
value = caget(cmd)
|
|
if isinstance(value, str):
|
|
display_value = value
|
|
else:
|
|
# value = string(value) c ensure float
|
|
display_value = str(value)
|
|
print(comp + "_" + p + " = " + display_value)
|
|
# print(value)
|
|
except:
|
|
# print("Problem")
|
|
# value = float('nan')
|
|
nan_occurred = True
|
|
print(comp + p + " = NaN")
|
|
parameters[comp][p] = {"value": value, "tolerance": tol}
|
|
|
|
return parameters
|
|
|
|
def select_components(selected_components=None):
|
|
# Allows the user (or another function) to select one
|
|
# or more components either interactively or
|
|
# by providing a list. It validates the selection against
|
|
# the available components in the JSON file.
|
|
|
|
msg = "Select components: "
|
|
|
|
# 1 Load machine parameters
|
|
try:
|
|
with open(BEAMLINE_PARAMETERS_FILE, "r") as f:
|
|
machine_parameters = json.load(f, object_pairs_hook=OrderedDict)
|
|
except:
|
|
print("Error loading machine_parameters.json")
|
|
return None
|
|
|
|
# 2 Extract component names
|
|
all_components = list(machine_parameters.keys())
|
|
# print("Available components:")
|
|
# for comp in all_components:
|
|
# print("- " + comp)
|
|
|
|
# 3 determine components to display
|
|
if selected_components is None:
|
|
|
|
# user didn't specify -> use all from JSON
|
|
presented_to_select = all_components[:]
|
|
presented_to_select.append("all")
|
|
|
|
selected = get_string(msg, default=None, alternatives=presented_to_select, password=False)
|
|
# print(selected)
|
|
if selected is None:
|
|
print("Selection aborted by user.")
|
|
return None
|
|
elif selected == "all":
|
|
# Display components
|
|
print("Selected components:")
|
|
for comp in all_components:
|
|
print("- " + comp)
|
|
return all_components
|
|
|
|
else:
|
|
selected_components = [selected] if not isinstance(selected, list) else selected
|
|
print("Selected components:")
|
|
for comp in selected_components:
|
|
print("- " + comp)
|
|
return selected_components
|
|
|
|
elif selected_components == "all":
|
|
# Display components
|
|
print("Selected components:")
|
|
for comp in all_components:
|
|
print("- " + comp)
|
|
return all_components
|
|
|
|
else:
|
|
# ensure it is a list
|
|
if not isinstance(selected_components, list):
|
|
print("Error: selected_components must be a list of the form \"[\"Diag\", \"CMU\", ...]\" or \"all\".")
|
|
return
|
|
# validate each component
|
|
invalid = [c for c in selected_components if c not in all_components]
|
|
if invalid:
|
|
print("Error: Invalid component(s):")
|
|
for comp in invalid:
|
|
print("- " + comp)
|
|
|
|
print("Valid components are:")
|
|
for comp in all_components:
|
|
print("- " + comp)
|
|
|
|
return None
|
|
else:
|
|
print("Selected components:")
|
|
for comp in selected_components:
|
|
print("- " + comp)
|
|
return selected_components
|
|
|
|
|
|
def bml_display_current_settings(selected_components=None):
|
|
# Displays parameters for selected components.
|
|
# - Uses select_components() to choose components.
|
|
# - Prints each parameter with its value.
|
|
# - If a parameter value is missing or cannot be read, prints NaN.
|
|
|
|
# 1 Get the selected component
|
|
selection = select_components(selected_components)
|
|
if selection is None:
|
|
return # user cancelled or invalid input
|
|
|
|
# 2 Load the machine poarametrers JSON
|
|
try:
|
|
with open(BEAMLINE_PARAMETERS_FILE, "r") as f:
|
|
machine_parameters = json.load(f, object_pairs_hook=OrderedDict)
|
|
except:
|
|
print("Error loading machine_parameters.json")
|
|
return
|
|
|
|
# 3 Loop through the components and display their parameters
|
|
for comp in selection:
|
|
print("\nComponent: " + comp)
|
|
params = machine_parameters.get(comp, {})
|
|
if not params:
|
|
print(" No parameters found.")
|
|
continue
|
|
|
|
for key, param_info in params.items():
|
|
|
|
# param_info enthalt z.B. den read_cmd
|
|
read_cmd = param_info.get("read_cmd") # JSON muss fur jeden Parameter den entsprechenden Befehl enthalten
|
|
|
|
try:
|
|
display_value = caget(read_cmd)
|
|
print(key + " = " + str(display_value))
|
|
except:
|
|
display_value = "NaN"
|
|
# print(" " + key + ": " + display_value)
|
|
|
|
def bml_restore_saved_settings(selected_components=None):
|
|
# Restore parameter values from a previously saved JSON file.
|
|
# The user selects which components to restore, and only parameters
|
|
# marked as "restorable": true in machine_parameters.json will be written back.
|
|
|
|
restore_file, name_only = save_data_and_config(default_dir=DATA_DIR, default_name=None, save_dialog=False)
|
|
|
|
# 1 Select file
|
|
# restore_file = get_string(msg, default = DATA_FILE, alternatives = None, password = False)
|
|
# if path is None:
|
|
# print("Restore aborted: no file specified.")
|
|
# return
|
|
|
|
try:
|
|
with open(restore_file, "r") as f:
|
|
saved_data = json.load(f, object_pairs_hook=OrderedDict)
|
|
except:
|
|
print("Error loading restore file:", restore_file)
|
|
return
|
|
|
|
# 2 Load machine parameters
|
|
try:
|
|
with open(BEAMLINE_PARAMETERS_FILE, "r") as f:
|
|
machine_parameters = json.load(f, object_pairs_hook=OrderedDict)
|
|
except:
|
|
print("Error loading machine_parameters.json")
|
|
return
|
|
|
|
# 3 Select components
|
|
selection = select_components(selected_components)
|
|
|
|
if selection is None:
|
|
return # user cancelled or invalid input
|
|
|
|
# 4 Load the machine parameters JSON
|
|
try:
|
|
with open(BEAMLINE_PARAMETERS_FILE, "r") as f:
|
|
machine_parameters = json.load(f, object_pairs_hook=OrderedDict)
|
|
except:
|
|
print("Error loading machine_parameters.json")
|
|
return
|
|
|
|
# 5 Restore loop
|
|
for comp in selection:
|
|
# print("\nComponent: " + comp)
|
|
params = machine_parameters.get(comp, {})
|
|
if not params:
|
|
print(" No parameters found.")
|
|
continue
|
|
|
|
saved_params = saved_data.get(comp, {})
|
|
if not saved_params:
|
|
print(" No saved values for this component.")
|
|
continue
|
|
|
|
for key, param_info in params.items():
|
|
|
|
if not param_info.get("restorable", False):
|
|
continue
|
|
|
|
# get saved value
|
|
saved_entry = saved_params.get(key, None)
|
|
if saved_entry is not None and 'value' in saved_entry:
|
|
saved_value = saved_entry['value']
|
|
else:
|
|
saved_value = "NaN"
|
|
|
|
# param_info enthalt z.B. den read_cmd
|
|
read_cmd = param_info.get("read_cmd") # JSON muss fur jeden Parameter den entsprechenden Befehl enthalten
|
|
write_cmd = param_info.get("write_cmd") # JSON muss fur jeden Parameter den entsprechenden Befehl enthalten
|
|
tolerance = param_info.get("tolerance")
|
|
|
|
try:
|
|
display_value = caget(read_cmd)
|
|
# print(read_cmd + " = " + str(display_value) + ", saved value = " + str(saved_value))
|
|
# difference = float(display_value) - float(saved_value)
|
|
# compute difference if possible
|
|
if saved_value != "NaN" and display_value != "NaN":
|
|
try:
|
|
difference = abs(float(display_value) - float(saved_value))
|
|
except:
|
|
difference = "NaN"
|
|
else:
|
|
difference = "NaN"
|
|
# print(read_cmd + " = " + str(display_value) + ", diff = " + str(round(difference, 5)) + ", tolerance = " + str(round(tolerance, 5)))
|
|
if float(difference) > float(tolerance):
|
|
print(key + " - Not OK. Set to " + str(round(saved_value, 5)))
|
|
write_cmd_new = "\"" + write_cmd + "\""
|
|
# print(write_cmd_new)
|
|
caput(write_cmd, float(saved_value))
|
|
check_restored_value = caget(read_cmd)
|
|
print(key + " - Reads now: " + str(check_restored_value))
|
|
else:
|
|
print(key + " - OK.")
|
|
except:
|
|
display_value = "NaN"
|
|
# print(" " + key + ": " + display_value)
|
|
|
|
|
|
def bml_display_saved_settings(selected_components=None):
|
|
# Diplay parameter values from a previously saved JSON file.
|
|
# The user selects which components to restore, and only parameters
|
|
# marked as "restorable": true in machine_parameters.json will be written back.
|
|
|
|
# msg = "Open *.json configuration file ..."
|
|
|
|
restore_file, name_only = save_data_and_config(default_dir=DATA_DIR, default_name=None, save_dialog=False)
|
|
# 1 Select file
|
|
# restore_file = get_string(msg, default = "/sls/X11MA/data/X11MA/scans/2511/0012.json", alternatives = None, password = False)
|
|
# path = get_string(msg, default = DATA_FILE, alternatives = None, password = False)
|
|
# if restore_file is None:
|
|
# print("Restore aborted: no file specified.")
|
|
# return
|
|
|
|
try:
|
|
with open(restore_file, "r") as f:
|
|
saved_data = json.load(f, object_pairs_hook=OrderedDict)
|
|
except:
|
|
print("Error loading restore file:", restore_file)
|
|
return
|
|
|
|
# 2 Load machine parameters
|
|
try:
|
|
with open(BEAMLINE_PARAMETERS_FILE, "r") as f:
|
|
machine_parameters = json.load(f, object_pairs_hook=OrderedDict)
|
|
except:
|
|
print("Error loading machine_parameters.json")
|
|
return
|
|
|
|
# 3 Select components
|
|
selection = select_components(selected_components)
|
|
|
|
if selection is None:
|
|
return # user cancelled or invalid input
|
|
|
|
# 4 Load the machine parameters JSON
|
|
try:
|
|
with open(BEAMLINE_PARAMETERS_FILE, "r") as f:
|
|
machine_parameters = json.load(f, object_pairs_hook=OrderedDict)
|
|
except:
|
|
print("Error loading machine_parameters.json")
|
|
return
|
|
|
|
# 5 Display loop
|
|
for comp in selection:
|
|
print("\nComponent: " + comp)
|
|
params = machine_parameters.get(comp, {})
|
|
if not params:
|
|
print(" No parameters found.")
|
|
continue
|
|
|
|
saved_params = saved_data.get(comp, {})
|
|
if not saved_params:
|
|
print(" No saved values for this component.")
|
|
continue
|
|
|
|
for key, param_info in params.items():
|
|
|
|
# if not param_info.get("restorable", False):
|
|
# continue
|
|
|
|
# get saved value
|
|
saved_entry = saved_params.get(key, None)
|
|
if saved_entry is not None and 'value' in saved_entry:
|
|
saved_value = saved_entry['value']
|
|
|
|
else:
|
|
saved_value = "NaN"
|
|
|
|
print(key + " was: " + str(saved_value))
|
|
|
|
|
|
def bml_show_difference_to_saved_settings(selected_components=None):
|
|
# Restore parameter values from a previously saved JSON file.
|
|
# The user selects which components to restore, and only parameters
|
|
# marked as "restorable": true in machine_parameters.json will be written back.
|
|
|
|
restore_file, name_only = save_data_and_config(default_dir=DATA_DIR, default_name=None, save_dialog=False)
|
|
|
|
# restore_file = get_string(msg, default = "/sls/X11MA/data/X11MA/scans/2511/0012.json", alternatives = None, password = False)
|
|
if restore_file is None:
|
|
print("Restore aborted: no file specified.")
|
|
return
|
|
|
|
try:
|
|
with open(restore_file, "r") as f:
|
|
saved_data = json.load(f, object_pairs_hook=OrderedDict)
|
|
except:
|
|
print("Error loading restore file:", restore_file)
|
|
return
|
|
|
|
# 2 Load machine parameters
|
|
try:
|
|
with open(BEAMLINE_PARAMETERS_FILE, "r") as f:
|
|
machine_parameters = json.load(f, object_pairs_hook=OrderedDict)
|
|
except:
|
|
print("Error loading machine_parameters.json")
|
|
return
|
|
|
|
# 3 Select components
|
|
selection = select_components(selected_components)
|
|
|
|
if selection is None:
|
|
return # user cancelled or invalid input
|
|
|
|
# 4 Load the machine parameters JSON
|
|
try:
|
|
with open(BEAMLINE_PARAMETERS_FILE, "r") as f:
|
|
machine_parameters = json.load(f, object_pairs_hook=OrderedDict)
|
|
except:
|
|
print("Error loading machine_parameters.json")
|
|
return
|
|
|
|
# 5 Restore loop
|
|
for comp in selection:
|
|
print("\nComponent: " + comp)
|
|
params = machine_parameters.get(comp, {})
|
|
if not params:
|
|
print(" No parameters found.")
|
|
continue
|
|
|
|
saved_params = saved_data.get(comp, {})
|
|
if not saved_params:
|
|
print(" No saved values for this component.")
|
|
continue
|
|
|
|
for key, param_info in params.items():
|
|
|
|
# if not param_info.get("restorable", False):
|
|
# continue
|
|
|
|
# get saved value
|
|
saved_entry = saved_params.get(key, None)
|
|
if saved_entry is not None and 'value' in saved_entry:
|
|
saved_value = saved_entry['value']
|
|
else:
|
|
saved_value = "NaN"
|
|
|
|
# param_info enthalt z.B. den read_cmd
|
|
read_cmd = param_info.get("read_cmd") # JSON muss fur jeden Parameter den entsprechenden Befehl enthalten
|
|
# write_cmd = param_info.get("write_cmd") # JSON muss fur jeden Parameter den entsprechenden Befehl enthalten
|
|
tolerance = param_info.get("tolerance")
|
|
|
|
try:
|
|
display_value = caget(read_cmd)
|
|
# print(read_cmd + " = " + str(display_value) + ", saved value = " + str(saved_value))
|
|
# difference = float(display_value) - float(saved_value)
|
|
# compute difference if possible
|
|
if saved_value != "NaN" and display_value != "NaN":
|
|
try:
|
|
difference = abs(float(display_value) - float(saved_value))
|
|
except:
|
|
difference = "NaN"
|
|
else:
|
|
difference = "NaN"
|
|
# print(read_cmd + " = " + str(display_value) + ", diff = " + str(round(difference, 5)) + ", tolerance = " + str(round(tolerance, 5)))
|
|
if float(difference) > float(tolerance):
|
|
print(key + " - Differs from saved value: " + str(round(saved_value, 5)))
|
|
# write_cmd_new = "\"" + write_cmd + "\""
|
|
# print(write_cmd_new)
|
|
# caput(write_cmd, float(saved_value))a
|
|
# check_restored_value = caget(read_cmd)
|
|
# print(key + " - Reads now: " + str(check_restored_value))
|
|
else:
|
|
print(key + " - OK.")
|
|
except:
|
|
display_value = "NaN"
|
|
# print(" " + key + ": " + display_value)
|
|
|