fix: ipython startup #7

Merged
wakonig_k merged 1 commits from fix/cleanup_startup into main 2026-01-17 18:25:38 +01:00
2 changed files with 152 additions and 145 deletions

View File

@@ -1,75 +1,57 @@
import builtins
import collections
import functools
import json
import math
import pathlib
import numpy
from bec_ipython_client.main import BECClientPrompt
from bec_ipython_client.prettytable import PrettyTable
__all__ = [
'setlat',
'setlambda',
'setmode',
'freeze',
'unfreeze',
'br',
'ubr',
'mvhkl',
'umvhkl',
'ca',
'wh',
'pa',
'orientAdd',
'orientRemove',
'orientShow',
'orientFit',
'ct'
"setlat",
"setlambda",
"setmode",
"freeze",
"unfreeze",
"br",
"ubr",
"mvhkl",
"umvhkl",
"ca",
"wh",
"pa",
"orientAdd",
"orientRemove",
"orientShow",
"orientFit",
"ct",
]
bec = builtins.__dict__.get("bec")
dev = builtins.__dict__.get("dev")
scans = builtins.__dict__.get("scans")
class BECClientPromptDiffractometer(BECClientPrompt):
@property
def username(self):
"""current username"""
if "x04v" in dev:
return "x04v"
if "x04h" in dev:
return "x04h"
return "demo"
bec._ip.prompts = BECClientPromptDiffractometer(ip=bec._ip, username="demo", client=bec._client, status=1)
# check for diffractometer device
diffract = None
if dev is not None:
if 'x04h' in dev:
if "x04h" in dev:
diffract = dev.x04h
elif 'x04v' in dev:
elif "x04v" in dev:
diffract = dev.x04v
if diffract is not None:
RealPosition = collections.namedtuple('RealPosition', ' '.join(diffract.get_real_positioners()))
RealPosition = collections.namedtuple("RealPosition", " ".join(diffract.get_real_positioners()))
def freeze(
angle: float | None
):
def freeze(angle: float | None):
"""
Freeze the value of the mode dependent angle, so when calculating motor positions
corresponding to an arbitrary (H, K, L ), the angle will be reset to the frozen value
Freeze the value of the mode dependent angle, so when calculating motor positions
corresponding to an arbitrary (H, K, L ), the angle will be reset to the frozen value
before the calculation no matter what the current position of the diffractometer.
"""
diffract.freeze(angle)
def unfreeze():
"""
Subsequent angle calculations will use whatever the current value of the associated
@@ -77,74 +59,69 @@ def unfreeze():
"""
diffract.unfreeze()
def setlat(
a: float, b: float, c: float, alpha: float, beta: float, gamma: float
):
def setlat(a: float, b: float, c: float, alpha: float, beta: float, gamma: float):
"""
Set sample lattice parameters
"""
diffract.set_lattice((a, b, c, alpha, beta, gamma))
def setlambda(
wavelength: float
):
def setlambda(wavelength: float):
"""
Set the x-ray wavelength (in Angstroms)
"""
if wavelength <= 0:
print('Invalid input: wavelength <=0!')
print("Invalid input: wavelength <=0!")
return
current_wavelength = diffract.get_wavelength()
if math.isclose(wavelength, current_wavelength):
print(f'Still using {current_wavelength} A')
print(f"Still using {current_wavelength} A")
else:
diffract.set_wavelength(wavelength)
print(f'Lambda reset from {current_wavelength} to {wavelength} A')
print(f"Lambda reset from {current_wavelength} to {wavelength} A")
def setmode(
mode: int
):
def setmode(mode: int):
"""
Set the geometry mode
"""
if mode < 0 or mode > 2:
print('Valid mode is from 0 to 2')
print("Valid mode is from 0 to 2")
return
current_mode = diffract.get_mode()
if mode == current_mode:
print(f'Still using mode {current_mode}')
print(f"Still using mode {current_mode}")
else:
diffract.set_mode(mode)
print(f'Mode reset from {current_mode} to {mode}')
print(f"Mode reset from {current_mode} to {mode}")
def mvhkl(
h: float, k: float, l: float, auto=False
):
def mvhkl(h: float, k: float, l: float, auto=False):
"""
Move to the reciprocol space coordinates
"""
try:
angles = diffract.forward(h, k, l)[:-2]
except Exception as exc:
print(f'{h} {k} {l} is not obtainable: {exc}')
print(f"{h} {k} {l} is not obtainable: {exc}")
return
if not auto:
for axis, current, target in zip(RealPosition._fields, _currentPosition(), angles):
print('%7s = %9.4f --> %9.4f' % (axis, current, target))
print("%7s = %9.4f --> %9.4f" % (axis, current, target))
answer = input('Move to these values? [Y/n]: ')
if answer.startswith(('N', 'n')):
print('Move abandoned.')
answer = input("Move to these values? [Y/n]: ")
if answer.startswith(("N", "n")):
print("Move abandoned.")
return
br(h, k, l)
def br(
h: float, k: float, l: float
):
def br(h: float, k: float, l: float):
"""
Move to the reciprocol space coordinates
"""
@@ -156,9 +133,8 @@ def br(
scans.mv(*args, relative=False)
def ubr(
h: float, k: float, l: float
):
def ubr(h: float, k: float, l: float):
"""
Move to the reciprocol space coordinates with updates
"""
@@ -170,44 +146,43 @@ def ubr(
scans.umv(*args, relative=False)
def umvhkl(
h: float, k: float, l: float, auto=False
):
def umvhkl(h: float, k: float, l: float, auto=False):
"""
Move to the reciprocol space coordinates with updates
"""
try:
angles = diffract.forward(h, k, l)[:-2]
except Exception as exc:
print(f'{h} {k} {l} is not obtainable: {exc}')
print(f"{h} {k} {l} is not obtainable: {exc}")
return
if not auto:
for axis, current, target in zip(RealPosition._fields, _currentPosition(), angles):
print('%7s = %9.4f --> %9.4f' % (axis, current, target))
print("%7s = %9.4f --> %9.4f" % (axis, current, target))
answer = input('Move to these values? [Y/n]: ')
if answer.startswith(('N', 'n')):
print('Move abandoned.')
answer = input("Move to these values? [Y/n]: ")
if answer.startswith(("N", "n")):
print("Move abandoned.")
return
ubr(h, k, l)
def ca(
h: float, k: float, l: float
):
def ca(h: float, k: float, l: float):
"""
Calculate angle positions for a given point in reciprocol space
"""
angles = diffract.forward(h, k, l)
print("\nCalculated positions:\n")
print(f'H K L = {h} {k} {l}')
print('BetaIn = %.5f BetaOut = %.5f' %(angles[-2], angles[-1]))
print('Lambda = %.3f' % diffract.get_wavelength())
print(f"H K L = {h} {k} {l}")
print("BetaIn = %.5f BetaOut = %.5f" % (angles[-2], angles[-1]))
print("Lambda = %.3f" % diffract.get_wavelength())
print()
_showAngles(angles[:-2])
def wh():
"""
Show where principal axes and reciprocal space
@@ -218,41 +193,45 @@ def wh():
betaIn = diffract.betaIn.position
betaOut = diffract.betaOut.position
print(f'H K L = {h:.4f} {k:.4f} {l:.4f}')
print('BetaIn = %.5f BetaOut = %.5f' %(betaIn, betaOut))
print('Lambda = %.3f' % diffract.get_wavelength())
print(f"H K L = {h:.4f} {k:.4f} {l:.4f}")
print("BetaIn = %.5f BetaOut = %.5f" % (betaIn, betaOut))
print("Lambda = %.3f" % diffract.get_wavelength())
print()
_showAngles()
def pa():
"""
Show geometry parameters
"""
if diffract.name == 'x04v':
print('x04v (Newport Microcontrols 2+3 at SLS) vertical geometry')
elif diffract.name == 'x04h':
print('x04h (Newport Microcontrols 2+3 at SLS) horizontal geometry')
if diffract.name == "x04v":
print("x04v (Newport Microcontrols 2+3 at SLS) vertical geometry")
elif diffract.name == "x04h":
print("x04h (Newport Microcontrols 2+3 at SLS) horizontal geometry")
match mode := diffract.get_mode():
case 0:
print(f' BetaIn Fixed (mode {mode})')
print(f" BetaIn Fixed (mode {mode})")
case 1:
print(f' BetaOut Fixed (mode {mode})')
print(f" BetaOut Fixed (mode {mode})")
case 2:
print(f' BetaIn equals BetaOut (mode {mode})')
print(f" BetaIn equals BetaOut (mode {mode})")
if beta_frozen := diffract.get_frozen():
print(f' Frozen coordinate: {beta_frozen}')
print(f" Frozen coordinate: {beta_frozen}")
def orientShow():
"""
Display list of measured reflections
"""
print('\n(Using lattice constants:)')
print("\n(Using lattice constants:)")
lattice = diffract.get_lattice()
print('a = %.4g, b = %.4g, b = %.4g, alpha = %.6g, beta = %.6g, gamma = %.6g' %
(lattice[0], lattice[1], lattice[2], lattice[3], lattice[4], lattice[5]))
print(
"a = %.4g, b = %.4g, b = %.4g, alpha = %.6g, beta = %.6g, gamma = %.6g"
% (lattice[0], lattice[1], lattice[2], lattice[3], lattice[4], lattice[5])
)
print("\n------------------------------------------------\n")
@@ -263,17 +242,15 @@ def orientShow():
_showUB()
def orientRemove(
h: float, k: float, l: float
):
def orientRemove(h: float, k: float, l: float):
"""
Remove a measured reflection from the list
"""
diffract.remove_reflection(h, k, l)
def orientAdd(
h: float, k: float, l: float, *args
):
def orientAdd(h: float, k: float, l: float, *args):
"""
Add a reflection to the list of measured reflections
"""
@@ -282,63 +259,67 @@ def orientAdd(
response = diffract.real_position
# The original return value is of namedtuple type,
# which gets serialized to a dictionary by the device server.
angles = tuple(response['values'][axis] for axis in response['fields'] if axis != 'nu')
angles = tuple(response["values"][axis] for axis in response["fields"] if axis != "nu")
if len(angles) < 4:
print('Please specify all angles')
print("Please specify all angles")
return
diffract.add_reflection(h, k, l, angles)
def orientSave(
filename: str
):
def orientSave(filename: str):
"""
Save the current reflections
"""
configuration = {}
configuration['geometry'] = diffract.name
configuration['wavelength'] = diffract.get_wavelength()
configuration['lattice'] = diffract.get_lattice()
configuration['reflections'] = diffract.get_reflections()
configuration["geometry"] = diffract.name
configuration["wavelength"] = diffract.get_wavelength()
configuration["lattice"] = diffract.get_lattice()
configuration["reflections"] = diffract.get_reflections()
filepath = pathlib.Path(filename)
if filepath.exists():
answer = input('File "%s" already exists. Do you want to overwrite it? [y/N]: ' %(filepath.absolute()))
if not answer.startswith(('Y', 'y')):
answer = input(
'File "%s" already exists. Do you want to overwrite it? [y/N]: ' % (filepath.absolute())
)
if not answer.startswith(("Y", "y")):
return
with open(filepath, 'w') as f:
with open(filepath, "w") as f:
json.dump(configuration, f)
def orientLoad(
filename: str
):
def orientLoad(filename: str):
"""
Load relfections from file
"""
with open(filename, 'r') as f:
with open(filename, "r") as f:
configuration = json.load(f)
if configuration['geometry'] != diffract.name:
print('Saved orientation is for a different geometry "%s", current is "%s".' % configuration['geometry'], diffract.name)
if configuration["geometry"] != diffract.name:
print(
'Saved orientation is for a different geometry "%s", current is "%s".'
% configuration["geometry"],
diffract.name,
)
return
# save current wavelength, lattice and reflections
saved_wavelength = diffract.get_wavelength()
saved_lattice = diffract.get_lattice()
saved_reflections = diffract.get_reflections()
try:
diffract.set_lattice(configuration['lattice'])
diffract.set_lattice(configuration["lattice"])
diffract.clear_reflections()
for reflection in configuration['reflections']:
for reflection in configuration["reflections"]:
diffract.add_reflection(*reflection)
_showReflections(configuration['reflections'])
_showReflections(configuration["reflections"])
print("\n------------------------------------------------\n")
# set wavelength temporarily for orientFit and restore later
diffract.set_wavelength(configuration['wavelength'])
diffract.set_wavelength(configuration["wavelength"])
orientFit()
except Exception as exc:
# restore saved lattice and reflections
@@ -352,6 +333,7 @@ def orientLoad(
# restore wavelength
diffract.set_wavelength(saved_wavelength)
def orientFit():
"""
Fit UB matrix from given reflections
@@ -364,19 +346,22 @@ def orientFit():
diffract.compute_UB()
_showUB()
def ct(exp_time: float):
"""
Acquire all detectors
"""
scans.acquire(exp_time=exp_time)
def _showUB():
UB = diffract.get_UB()
print('Orientation matrix by row:')
print(' Row 1: %8.5f %8.5f %8.5f' % (UB[0,0], UB[0,1], UB[0,2]))
print(' Row 2: %8.5f %8.5f %8.5f' % (UB[1,0], UB[1,1], UB[1,2]))
print(' Row 3: %8.5f %8.5f %8.5f' % (UB[2,0], UB[2,1], UB[2,2]))
print("Orientation matrix by row:")
print(" Row 1: %8.5f %8.5f %8.5f" % (UB[0, 0], UB[0, 1], UB[0, 2]))
print(" Row 2: %8.5f %8.5f %8.5f" % (UB[1, 0], UB[1, 1], UB[1, 2]))
print(" Row 3: %8.5f %8.5f %8.5f" % (UB[2, 0], UB[2, 1], UB[2, 2]))
def _showAngles(angles=None):
if angles is None:
@@ -384,23 +369,25 @@ def _showAngles(angles=None):
table = PrettyTable(RealPosition._fields, padding=12)
print(table.get_header())
text = tuple(f'{x:9.4f}' for x in angles)
text = tuple(f"{x:9.4f}" for x in angles)
print(table.get_row(*text))
def _currentPosition():
response = diffract.real_position
# The original return value is of namedtuple type,
# which gets serialized to a dictionary by the device server.
angles = RealPosition(*(response['values'][axis] for axis in response['fields']))
angles = RealPosition(*(response["values"][axis] for axis in response["fields"]))
return angles
def _showReflections(reflections):
print('The defined reflections are:')
header = ['h', 'k', 'l'] + diffract.real_position['fields'][:-1]
print("The defined reflections are:")
header = ["h", "k", "l"] + diffract.real_position["fields"][:-1]
table = PrettyTable(header, padding=12)
print(' ', table.get_header())
print(" ", table.get_header())
for reflection in reflections:
h, k, l, angles = reflection
text = [f'{h:9.4f}', f'{k:9.4f}', f'{l:9.4f}'] + [f'{x:9.4f}' for x in angles]
print(' ', table.get_row(*text))
text = [f"{h:9.4f}", f"{k:9.4f}", f"{l:9.4f}"] + [f"{x:9.4f}" for x in angles]
print(" ", table.get_row(*text))

View File

@@ -34,7 +34,27 @@ to setup the prompts.
"""
# pylint: disable=invalid-name, unused-import, import-error, undefined-variable, unused-variable, unused-argument, no-name-in-module
import builtins
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from bec_ipython_client.main import BECIPythonClient
bec: BECIPythonClient = BECIPythonClient()
dev = bec.device_manager.devices
scans = bec.scans
else:
bec = builtins.__dict__.get("bec")
dev = builtins.__dict__.get("dev")
scans = builtins.__dict__.get("scans")
bec.load_high_level_interface("bec_hli")
bec.load_high_level_interface("spec_hli")
bec.load_high_level_interface("hkl_hli")
if "x04v" in dev:
bec._ip.prompts.session_name = "x04v"
elif "x04h" in dev:
bec._ip.prompts.session_name = "x04h"