481 lines
18 KiB
Python
Executable File
481 lines
18 KiB
Python
Executable File
from collections import OrderedDict
|
||
import os
|
||
import json
|
||
|
||
# This script contains seveal functions:
|
||
# 1 bml_save_current_settings()
|
||
# 2 (select_components(selected_components=None) - is called by the following functions)
|
||
# 3 bml_display_current_settings(selected_components=None)
|
||
# 4 bml_restore_saved_settings(selected_components=None)
|
||
# 5 bml_display_saved_settings(selected_components=None)
|
||
# 6 bml_show_difference_to_saved_settings(selected_components=None)
|
||
# see also Python Projekte/Strings in Datei speichern
|
||
|
||
BEAMLINE_PARAMETERS_FILE = "/sls/X11MA/data/X11MA/pshell/home/script/beamline_alignment/bml_align_params.json"
|
||
DATA_FILE = "/sls/X11MA/data/X11MA/pshell/home/data/2025_11/20251113/Monocam_AU_083.json"
|
||
#DATA_FILE = "/sls/X11MA/data/X11MA/scans/2511/0081.json"
|
||
|
||
|
||
def bml_save_current_settings():
|
||
|
||
#Allows the user to save relevant beamline parameters in aJSON file.
|
||
|
||
msg = "Save as ..."
|
||
# User inputs the file path
|
||
path = get_string(msg, default = DATA_FILE, alternatives = None, password = False)
|
||
|
||
# 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 machine
|
||
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")
|
||
|
||
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 components (interactive or via argument)
|
||
selection = select_components(selected_components)
|
||
if selection is None:
|
||
return # user cancelled or invalid input
|
||
|
||
# 2️ 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
|
||
|
||
# 3️ Loop through 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 enthält z.B. den read_cmd
|
||
read_cmd = param_info.get("read_cmd") # JSON muss für 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.
|
||
|
||
msg = "Open *.json configuration file ..."
|
||
|
||
# 1 Select file
|
||
restore_file = 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 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 enthält z.B. den read_cmd
|
||
read_cmd = param_info.get("read_cmd") # JSON muss für jeden Parameter den entsprechenden Befehl enthalten
|
||
write_cmd = param_info.get("write_cmd") # JSON muss für 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 ..."
|
||
|
||
# 1 Select file
|
||
#restore_file = get_string(msg, default = "/sls/X11MA/data/X11MA/scans/2511/0012.json", alternatives = None, password = False)
|
||
restore_file = 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.
|
||
|
||
msg = "Open *.json configuration file ..."
|
||
|
||
# 1 Select file
|
||
restore_file = get_string(msg, default = DATA_FILE, alternatives = None, password = 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 enthält z.B. den read_cmd
|
||
read_cmd = param_info.get("read_cmd") # JSON muss für jeden Parameter den entsprechenden Befehl enthalten
|
||
# write_cmd = param_info.get("write_cmd") # JSON muss für 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))
|
||
# 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)
|
||
|
||
|
||
# print("Component:", comp)
|
||
# run('beamline_init/with_x-rays/functions/SlitCalib.py') |