Files
x11ma/script/beamline_alignment/beamline_configuration.py
gac-x11ma 8ecd1f36c6 Startup
2025-11-19 10:59:01 +01:00

481 lines
18 KiB
Python
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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')