Commit 09a07487 authored by bliss administrator's avatar bliss administrator
Browse files

start committing for xas/xes and experiment

parent f3f78e1e
import numpy as np
from silx import io
from id26.scripts.beamline_settings import ID26Settings
from bliss import setup_globals
from bliss.common.standard import sync, move
from bliss import current_session
from bliss.shell.standard import umv
from id26.scripts.energy import energytoangle
my_tolerance = 0.002
#al = user_script_load('align.py', export_global = False)
# TODO, questions?
# checking only for HDM1 layer (hex1z position). What if others wrong?
# is there a better way?
#yes_or_no_line_input = setup_globals.yes_or_no_line_input
_AXES_NAMES_DICT = {
'undulators':['u35a', 'u35b', 'u35c', 't35a', 't35b'],
'optics slits gaps':['pvg', 'phg', 'ss1vg', 'ss1hg','hipsvg', 'hipshg', 'ss2vg', 'ss2hg'],#added ss1vg
# 'optics slits offsets': [ 'pvo', 'pho', 'ss1vo', 'ss1ho', 'hipsvo', 'hipsho','ss2vo', 'ss2ho'],
'optics slits offsets': ['ss1ho', 'hipsvo', 'hipsho','ss2vo', 'ss2ho'], # only move motors that depend on our alignment, pvo, phg, ss1vo depend on machine
'optics TY t00 ppy':['TY','t00y', 'ppy', 't00z'], # to be added i00z,
'optics mono': ['TH2', 'CHI2', 'mono', 'monox'], #mono or energy?
'optics mirror angles': [ 'rot1z','rot2z','rot3y','rot4z','hex4tz'],
'optics stripes':['hex1z','hex2z','hex3ty','rot4y'], #where else to put rot4y?
# 'mirror centers':['hex1y', 'hex2y','hex3z','hex4y'],
'mirror centers':['hex2y','hex3z','hex4y'], # only move motors that depend on our alignment, hex1y depends on machine
'mirror_benders':['hfm2u', 'hfm2d', 'vfm3u', 'vfm3d'],
'optics attenuators':['patt1', 'patt3'],
'foils':['foil00','foil01','e0foil'],
'KB mirrors':['hfm2u', 'hfm2d', 'vfm3u', 'vfm3d'],
'TEXS motors':['FY','FZ'], # to be added foil0t, i0t, maybe also 'xes_en_texs'?
'EH2_motors':['framety','e2boxz','e2vo', 'e2ho','foil02', 'e2boxy', 'sz'] #'xes_en' ?
}
if current_session.name in ['optics', 'eh2', 'texs']:
PVG = setup_globals.pvg
PVO = setup_globals.pvo
PHG = setup_globals.phg
PHO = setup_globals.pho
HIPSVG = setup_globals.hipsvg
HIPSVO = setup_globals.hipsvo
HIPSHG = setup_globals.hipshg
HIPSHO = setup_globals.hipsho
SS1UP = setup_globals.ss1up
SS1DOWN = setup_globals.ss1down
SS1VG = setup_globals.ss1vg
SS1VO = setup_globals.ss1vo
SS1HG = setup_globals.ss1hg
SS1HO = setup_globals.ss1ho
SS2VG = setup_globals.ss2vg
SS2VO = setup_globals.ss2vo
SS2HG = setup_globals.ss2hg
SS2HO = setup_globals.ss2ho
U35A = setup_globals.u35a
U35B = setup_globals.u35b
U35C = setup_globals.u35c
T35A = setup_globals.t35a
T35B = setup_globals.t35b
# some offsets and default values are in beamline_configuration/miscellaneous/align_vars.yml/id26align_calc_param
ID26ALIGN_CALC_PARAM = setup_globals.id26align_calc_param
ID26ALIGN_DISTANCE = setup_globals.id26align_distance
#_OPTICS_SLITS_GAPS = ['pvg', 'phg', 'ss1vg', 'ss1hg','hipsvg', 'hipshg', 'ss2vg', 'ss2hg']#added ss1vg
#_OPTICS_SLITS_OFFSETS = [ 'pvo', 'pho', 'ss1vo', 'ss1ho', 'hipsvo', 'hipsho','ss2vo', 'ss2ho']
#_OPTICS_AXES_NAMES = _OPTICS_SLITS_GAPS + _OPTICS_SLITS_OFFSETS + ['TY','t00y', 'ppy', 't00z', # to be added i00z,
#'patt1', 'patt3',
#'rot1z','rot2z','hex1y','hex1z','hex2z', 'hex2y','hex3ty','rot3y','hex3z','rot4y','rot4z','hex4y','hex4tz', 'TH2', 'CHI2', 'energy',
#'monox','FY','FZ','foil00','foil01','e0foil', 'hfm2u', 'hfm2d', 'vfm3u', 'vfm3d','phfm','pvfm']
## to be added i0tz, foil0t
if current_session.name in ['optics', 'eh2']:
SVG = setup_globals.e2vg
SHG = setup_globals.e2hg
XES_EN = setup_globals.xes_en
_AXES_NAMES_DICT['sample_slits'] = ['framety','e2boxz','e2vo', 'e2ho','foil02'] #'xes_en' ?
elif current_session.name in ['texs']:
SVG = setup_globals.tsvg
SHG = setup_globals.tshg
XES_EN = setup_globals.xes_en_texs
_AXES_NAMES_DICT['sample_slits'] = ['tsvo', 'tsho']
_AXES_NAMES = np.sum([*_AXES_NAMES_DICT.values()])
_EXTRA_KEYS = ['mirror_layers', 'mono_crystal','u35a_track','u35b_track',
'u35c_track','u35a_harmonic','u35b_harmonic','u35c_harmonic']
def get_hdm1_mirror_layer(hex1z_pos):
# note: in spec the "good" positions were <-7.55 Pd, >3.55 Pt
if hex1z_pos < -18:
print('Hex1z value is wrong.')
raise ValueError
elif hex1z_pos < -6:
mirror_layer = 'Pd'
elif hex1z_pos < 6:
mirror_layer = 'Si'
elif hex1z_pos < 18:
mirror_layer = 'Pt'
else:
print('Hex1z value is wrong.')
raise ValueError
return mirror_layer
def move_t00y_section(t00y_current_val, t00y_new_val, TY_new_val, ppy_new_val):
sync_hard_all()
umv(TY, t00y_current_val, ppy, t00y_current_val) # bring both TY and ppy to the current value of t00y
umv(TY, t00y_new_val, ppy, t00y_new_val, t00y, t00y_new_val) # bring all motors to the desired t00y
umv(TY, TY_new_val)
umv(ppy, ppy_new_val)
class ID26Experiment(ID26Settings):
# TODO: what about motor names which are already uppercase?
def __init__(self, name):
super().__init__(name, defaults=self.build_default_parameters())
# print ("Initialized XAbsorptionSpectroscopy")
self._optics_slits = [PVG, PVO, PHG, PHO, HIPSVO, HIPSVG, HIPSHO, HIPSHG, SS1HO, SS1HG, SS2VG, SS2VO, SS2HG, SS2HO]
self._experiment_slits = [SVG, SHG]
def __dir__(self):
return 'setup', 'save', 'load', 'remove', 'clear', 'update_from_current', 'update_from_h5', 'set_slits', 'move_slits'
def build_default_parameters(self):
default_params = {}
for one_name in _AXES_NAMES:
default_params[one_name] = None
for one_name in _EXTRA_KEYS:
default_params[one_name] = None
return default_params
def update_from_current(self):
'''
Function that sets starting parameter to the current motor positions
'''
sync(*_AXES_NAMES)
for one_name in _AXES_NAMES:
ax = current_session.config.get(one_name)
self[one_name] = ax.position
self['mirror_layers'] = get_hdm1_mirror_layer(current_session.config.get('hex1z').position)
self['mono_crystal'] = setup_globals.dcm.xtals.xtal_sel
self['u35a_track'] = setup_globals.u35a.track()
self['u35b_track'] = setup_globals.u35b.track()
self['u35c_track'] = setup_globals.u35c.track()
self['u35a_harmonic'] = setup_globals.u35a.harmonic()
self['u35b_harmonic'] = setup_globals.u35b.harmonic()
self['u35c_harmonic'] = setup_globals.u35c.harmonic()
def move_slits(self):
key_error = False
#ss1vg.move(self['ss1vg'])
SS1UP.move(1)
SS1DOWN.move(1)
for one_axis in self._optics_slits:
try:
one_axis.move(self[one_axis.name])
except KeyError:
print('ID26Experiment: {:s} key not defined. Nothing moved.'.format(one_axis.name))
key_error = True
if key_error is True:
print('If some key not defined, run ID26Experiment.update_slits() or run frontalign.')
def update_slits(self, *my_axes):
if not my_axes:
my_axes = self._optics_slits
for my_axis in my_axes:
my_axis.sync_hard()
self[my_axis.name] = my_axis.position
def update_from_h5(self, h5_fullname, scanno=None):
try: # if it is a specfile
sf = io.open(h5_fullname)
print(sf)
if scanno is None:
sf_label = sf.keys()[-1]
else:
sf_label = '/'+str(scanno)+'.1'
sf_dataset = sf[sf_label]
#energy_val = sf_dataset['instrument']['positioners']['energy'][()]
h5keys = sf_dataset['instrument']['positioners'].keys()
for name in _AXES_NAMES:
if name in h5keys:
positioner = sf_dataset['instrument']['positioners'][name][()]
if np.size(positioner)>1:
self[name] = positioner[0]
else:
self[name] = positioner
#TODO: special methods for _EXTRA_KEYS to write when metadata available
except OSError: # if it is not a h5 file
print(file_to_open + ' is not a valid HDF5 filename. Update not done.')
def move_with_confirm(self):
for ax_name in _AXES_NAMES:
sync(ax_name)
ax = current_session.config.get(ax_name)
if (ax.position - self[ax_name]) != 0:
msg = f'Do you want to move {ax_name} motor by {(self[ax_name] - ax.position):.4f} from {ax.position:.4f} to {self[ax_name]:.4f}?'
move_yes = yes_or_no_line_input(msg, defval = False)
if move_yes:
# TODO: umv when moving
umv(ax,self[ax_name])
else:
print(f'Motor position for {ax_name} has not changed')
def move_show(self):
for ax_name in _AXES_NAMES:
sync(ax_name)
ax = current_session.config.get(ax_name)
if (ax.position - self[ax_name]) != 0:
print(f'Motor {ax_name} will move by {(self[ax_name] - ax.position):.4f} from {ax.position:.4f} to {self[ax_name]:.4f}?')
else:
print(f'Motor position for {ax_name} has not changed')
def move(self,my_axis):
my_axis.sync_hard()
ax_name = my_axis.name
umv(my_axis, self[ax_name])
def move_all_together(self):
motion = ()
# first only slits gaps:
print('Moving all slits gaps')
for ax_name in _OPTICS_SLITS_GAPS:
motion += (ax_name, self[ax_name])
move(*motion)
# TODO: continue with groups of motors
def smart_move(self, confirm = True):
for ax_group_names, ax_group_values in _AXES_NAMES_DICT.items():
if confirm:
print("")
print("__________________________________________________")
print("")
msg = f'Next group \'{ax_group_names}\' contains motors {ax_group_values}. Do you want to move any of those?'
next_group = yes_or_no_line_input(msg, defval = False)
else:
next_group = True
if next_group:
motion = ()
for ax_name in ax_group_values:
ax = current_session.config.get(ax_name)
sync(ax_name)
if np.abs((ax.position - self[ax_name])) > my_tolerance:
msg = f'Do you want to move {ax_name} motor by {(self[ax_name] - ax.position):.4f} from {ax.position:.4f} to {self[ax_name]:.4f}?'
if confirm:
print("")
print("__________________________________________________")
print("")
move_yes = yes_or_no_line_input(msg, defval = False)
#print("move_yes", move_yes)
else:
move_yes = True
if move_yes:
# TODO: umv when moving
motion += (ax, self[ax_name])
#print("new motion", motion)
else:
print(f'Motor position for {ax_name} will not be changed')
msg = 'Ready to move?'
if confirm:
print("")
print("__________________________________________________")
print("")
do_move = yes_or_no_line_input(msg, defval = False)
else:
do_move = True
if do_move:
if ['TY', 't00y', 'ppy'] in ax_group_values:
print('ATTENTION: risk of pulling on bellows in the t00y section. Moving first to straighten all.')
t00y.sync_hard()
t00y_current_val = t00y.position
if self['t00y']:
t00y_new_val = self['t00y']
else:
t00y_new_val = t00y.position
if self['TY']:
TY_new_val = self['TY']
else:
TY_new_val = TY.position
if self['ppy']:
ppy_new_val = self['ppy']
else:
ppy_new_val = ppy.position
move_t00y_section(t00y_current_val, t00y_new_val, TY_new_val, ppy_new_val)
elif len(motion) == 0:
print("No motors to move")
else:
print("Moving motors", motion)
move(*motion)
def compare_pos(self,fname):
return()
def save_move_file(self,fname):
sync(*_AXES_NAMES)
with open(fname, 'w+') as fo:
for ax_name in _AXES_NAMES:
print(ax_name)
ax = current_session.config.get(ax_name)
fo.write(f'umv({ax_name}, {self[ax_name]:g}) # from current {ax.position:g} position\n')
def calc_move(self):
'''
Updates the ID26Experiment object with motor positions to move to according to extra keys
if an offset must be applied, it is loaded from the
id26align_calc_param object
optimum taper values
Returns the updated object (is that useful?)
id26align_calc_param are mostly offsets, see beacon miscellaneous/align_vars.yml
'''
# what about taper values?
# Offset values for alignment motors are definded below, as the
# starting values of pos_target object.
# Those are expected positions of the motor for white beam.
# Should all be zero for default motors alignment,
# except TY~16.15 (white beem between crystals).
# undulator position calculated for the current harmonic and offsets
# TODO: change to what comes from the menu
self['u35a'] = calc_undulator(self['energy'], U35A)
self['u35b'] = calc_undulator(self['energy'], U35B)
self['u35c'] = calc_undulator(self['energy'], U35C)
print(self['hdm1_angle'])
calc_phg_val = calc_phg(self["hdm1_angle"])
print('phg',calc_phg_val)
self['phg'] = calc_phg_val
calc_rot1z_val = calc_rot1z(ID26ALIGN_CALC_PARAM['rot1z'],self['hdm1_angle'])
print('rot1z', calc_rot1z_val)
self['rot1z'] = calc_rot1z_val
calc_ss1ho_val = calc_ss1ho(ID26ALIGN_CALC_PARAM['ss1ho'], self['rot1z'], ID26ALIGN_DISTANCE['hex1'], ID26ALIGN_DISTANCE['ss1'] )
print('ss1ho', calc_ss1ho_val)
self['ss1ho'] = calc_ss1ho_val
# TODO: takes only 1 harmonic, what if the user asks for different ones on each undu?
calc_patts_val = calc_patts(self['u35b_harmonic'], self['energy'])
print('diamond thickness to use: {}'.format( calc_patts_val[0]))
print('patt1', calc_patts_val[1])
print('patt3', calc_patts_val[2])
self['patt1'] = calc_patts_val[1]
self['patt3'] = calc_patts_val[2]
# undulators: depending on which ones to use
# switch to 'IN' for those in the list:
# TODO: get a list of existing undulator, set pos_target to 50 (i.e. out) for each
# calc_undu = calc_undulators(get_available_undulators())
# TODO: does this handle correctly the revolver?
# no calculation needed for energy
# next line not needed? if yes, just a local variable, calculate real motors from it
#mono_crystal = self["new_mono"]
# TODO: this is normally handled by the energy object but here we have to calculate
print('mono', energytoangle(self['energy']))
print('monox', setup_globals.monox_calc_ene(self["energy"]))
self['mono'] = energytoangle(self['energy'])
self['monox'] = setup_globals.monox_calc_ene(self["energy"])
calc_hex1z_val = calc_hex1z(ID26ALIGN_CALC_PARAM['hex1z'],self['mirror_layers'])
print('hex1z', calc_hex1z_val)
self['hex1z'] = calc_hex1z_val
calc_TY_val = calc_TY(ID26ALIGN_CALC_PARAM['TY'], self["mono_crystals"],self['rot1z'], ID26ALIGN_DISTANCE['hex1'], ID26ALIGN_DISTANCE['mono'] )
print('TY', calc_TY_val)
self['TY'] = calc_TY_val
# TODO: rewrite this
calc_TH2_val = calc_TH2(ID26ALIGN_CALC_PARAM['TH2_111'],ID26ALIGN_CALC_PARAM['TH2_311'], self["mono_crystals"])
print('TH2', calc_TH2_val)
self['TH2'] = calc_TH2_val
calc_CHI2_val = calc_CHI2(ID26ALIGN_CALC_PARAM['CHI2_111'],ID26ALIGN_CALC_PARAM['CHI2_311'], self["mono_crystals"])
print('CHI2', calc_CHI2_val)
self['CHI2'] = calc_CHI2_val
calc_t00y_val = calc_t00y(ID26ALIGN_CALC_PARAM['t00y'], self['rot1z'], ID26ALIGN_DISTANCE["hex1"], ID26ALIGN_DISTANCE["t00"] )
print('t00y', calc_t00y_val)
self['t00y'] = calc_t00y_val
# needs revision:
# calc_hips_val = calc_hips(ID26ALIGN_CALC_PARAM['hipsho'], self['rot1z'], ID26ALIGN_DISTANCE["hex1"], ID26ALIGN_DISTANCE["hips"], pos_target.position(t00y) )
# print('hipsho', calc_hips_val)
# pos_target.position(hipsho, calc_hips_val)
calc_ppy_val = calc_ppy(ID26ALIGN_CALC_PARAM['ppy'], self['hdm1_angle'], ID26ALIGN_DISTANCE["pp"], ID26ALIGN_DISTANCE["hex1"])
print('ppy ', calc_ppy_val)
self['ppy'] = calc_ppy_val
calc_hex2z_val = calc_hex2z(ID26ALIGN_CALC_PARAM['hex2z'], self["hfm2_angle"], self['mirror_layers'])
print('hex2z', calc_hex2z_val)
self['hex2z'] = calc_hex2z_val
calc_hex2y_val = calc_hex2y( ID26ALIGN_CALC_PARAM['hex2y'], self["rot1z"], ID26ALIGN_DISTANCE["hex1"], ID26ALIGN_DISTANCE["hex2"])
print('hex2y', calc_hex2y_val)
self['hex2y'] = calc_hex2y_val
calc_rot2z_val = calc_rot2z(ID26ALIGN_CALC_PARAM['rot2z'], self["rot1z"], self['hfm2_angle'])
print('rot2z', calc_rot2z_val)
self['rot2z'] = calc_rot2z_val
calc_hex3ty_val = calc_hex3ty(ID26ALIGN_CALC_PARAM['hex3ty'], self['rot1z'], self['rot2z'],
ID26ALIGN_DISTANCE['hex3'], ID26ALIGN_DISTANCE['hex2'], ID26ALIGN_DISTANCE['hex1'], self['mirror_layers'])
print('hex3ty', calc_hex3ty_val)
self['hex3ty'] = calc_hex3ty_val
calc_rot3y_val = calc_rot3y(ID26ALIGN_CALC_PARAM['rot3y'], self["vfm3_angle"])
print('rot3y', calc_rot3y_val)
self['rot3y'] = calc_rot3y_val
calc_rot4z_val = calc_rot4z(ID26ALIGN_CALC_PARAM['rot4z'], self["rot2z"], self['rot1z'] )
print('rot4z', calc_rot4z_val)
self['rot4z'] = calc_rot4z_val
calc_hex4y_val = calc_hex4y( ID26ALIGN_CALC_PARAM['hex2y'], self["rot1z"], self['rot2z'], ID26ALIGN_DISTANCE['hex4'], ID26ALIGN_DISTANCE["hex2"], ID26ALIGN_DISTANCE["hex1"])
print('hex4y', calc_hex4y_val)
self['hex4y']= calc_hex4y_val
calc_FY_val = calc_FY( ID26ALIGN_CALC_PARAM['FY'], self["rot1z"], self['rot2z'], ID26ALIGN_DISTANCE['texs'], ID26ALIGN_DISTANCE["hex2"], ID26ALIGN_DISTANCE["hex1"])
print('FY', calc_FY_val)
self['FY'] = calc_FY_val
calc_FZ_val = calc_FZ( ID26ALIGN_CALC_PARAM['FZ'], self["rot3y"],ID26ALIGN_DISTANCE['texs'], ID26ALIGN_DISTANCE["hex3"])
print('FZ', calc_FZ_val)
self['FZ'] = calc_FZ_val
calc_framety_val = calc_framety( ID26ALIGN_CALC_PARAM['framety'], self["rot1z"], self['rot2z'], ID26ALIGN_DISTANCE['spec'], ID26ALIGN_DISTANCE["hex2"], ID26ALIGN_DISTANCE["hex1"])
print('framety', calc_framety_val)
self['framety'] = calc_framety_val
calc_e2boxy_val = calc_e2boxy(ID26ALIGN_CALC_PARAM['e2boxy']) # e2boxy moves with framety
print('e2boxy', calc_e2boxy_val)
self['e2boxy'] = calc_e2boxy_val
calc_e2boxz_val = calc_e2boxz(ID26ALIGN_CALC_PARAM['e2boxy'], self['rot3y'], ID26ALIGN_DISTANCE['e2box'], ID26ALIGN_DISTANCE['hex3'])
print('e2boxz', calc_e2boxz_val)
self['e2boxz'] = calc_e2boxz_val
# TODO:
# calc_i01z_val = ...
print('needs to calc i01z')
# calc_sz_val = ...
print('needs to calc sz')
# TODO:
# what is this good for?
# self["align"] = "Mono: th2align"
#TODO
# 3: motors depending on HFM2 position
#if(self["rot2z"] == "out" ):
## HFM2: mirror moved out of beam by 8mm
#pos_target.position(hex2y, ID26ALIGN_CALC_PARAM['hex2y'] - 8)
## HFM2: mirror angle set parallel to the beam
#pos_target.position(rot2z, ID26ALIGN_CALC_PARAM['rot2z'] + 2*self["rot1z"])
#else:
#pos_target.position(rot2z, ID26ALIGN_CALC_PARAM['rot2z'] + 2*self["rot1z"]-self["rot2z"])
#tan_val = np.tan(2*(2*self["rot1z"]-pos_target.position_list()["rot2z"])/1000)
#pos_target.position(hex3ty, pos_target.position_list()['hex3ty'] - tan_val * (ID26ALIGN_DISTANCE["hex3"] -ID26ALIGN_DISTANCE["hex2"]))
#pos_target.position(rot4z, pos_target.position_list()['rot4z'] - 2*self["rot2z"])
#dist_val = (ID26ALIGN_DISTANCE["hex4"] -ID26ALIGN_DISTANCE["hex2"])
#pos_target.position(hex4y, pos_target.position_list()['hex4y'] + tan_val*dist_val)
#dist_val = (ID26ALIGN_DISTANCE["e2box"] -ID26ALIGN_DISTANCE["hex2"])
#pos_target.position(FY, pos_target.position_list()['FY'] - tan_val *(ID26ALIGN_DISTANCE["texs"] -ID26ALIGN_DISTANCE["hex2"]))
#pos_target.position(e2boxy, pos_target.position_list()['e2boxy'] )# e2boxy moves with framety
## pos_target.position(e2boxy, ID26ALIGN_CALC_PARAM['e2boxy' ] + tan_val * (ID26ALIGN_DISTANCE["e2box"] -ID26ALIGN_DISTANCE["hex1"]))
#dist_val = (ID26ALIGN_DISTANCE["spec"] -ID26ALIGN_DISTANCE["hex2"])
#pos_target.position(framety, pos_target.position_list()['framety'] - tan_val*dist_val)
## 4: motors depending on VFM3 positions
#if(self["rot3y"] == "out" ):
## mirror moved out of beam by 5mm
#pos_target.position(hex3z, ID26ALIGN_CALC_PARAM['hex3z'] - 5)
## mirror angle set parallel to the beam, i.e not moved from zero
#else:
#pos_target.position(rot3y, ID26ALIGN_CALC_PARAM['rot3y'] + self["rot3y"])
#tan_val = np.tan(2*self["rot3y"]/1000)
#pos_target.position(rot4y, ID26ALIGN_CALC_PARAM['rot4y'] + 2*self["rot3y"])
#pos_target.position(hex4tz, ID26ALIGN_CALC_PARAM['hex4tz'] + tan_val * (ID26ALIGN_DISTANCE["hex4"]-ID26ALIGN_DISTANCE["hex3"]))
#pos_target.position(FZ, ID26ALIGN_CALC_PARAM['FZ'] + tan_val * (ID26ALIGN_DISTANCE["texs"]-ID26ALIGN_DISTANCE["hex3"]))
#pos_target.position(e2boxz, ID26ALIGN_CALC_PARAM['e2boxz'] + tan_val * (ID26ALIGN_DISTANCE["e2box"]-ID26ALIGN_DISTANCE["hex3"]))
#pos_target.position(sz, ID26ALIGN_CALC_PARAM['sz'] + tan_val * (ID26ALIGN_DISTANCE["spec"]-ID26ALIGN_DISTANCE["hex3"]))
#pos_target.position(hex3z, ID26ALIGN_CALC_PARAM['hex3z'] )# do not touch
#pos_target.save(SCAN_SAVING.base_path,'id26align_target')
# TODO:
# calculate gaps
# for the moment take current positions to have the pos_target not empty:
# TODO: all possible undulators
# pos_target.update(u35u, u35d, u35m, t35u, t35m)
# TODO: calculate CHI2 but this is already done above!
#pos_target.update(CHI2)
return self
def calc_rot1z(offset, hdm1_angle):
return offset + hdm1_angle
def calc_phg(hdm1_angle):
return np.min([np.sin(hdm1_angle/1000)*620*0.9, 1.5])
def calc_ss1ho(offset, hdm1_angle, hdm1_pos, ss1_pos):
return -offset -np.tan(hdm1_angle/1000*2)*(ss1_pos -hdm1_pos)
def calc_patts(harmonic, energy_val):
print(type(harmonic), type(energy_val))
# Defining optimum thickness for higher harmonics (optimized for u35 undulators)
# patt is not a motor, it is the thickness of the diamond needed (in um)! Patt1 and patt3 will be moved then
patt_thickness = 0 # no patt if on the 1st harmonic of undulators
if harmonic == 1: # no patt on the fundamental:
patt_thickness = 0
patt1_pos = -15
patt3_pos = -15
else: #on higher undulator harmonics
if (energy_val > 19.5 or harmonic > 3):
patt_thickness =3500
elif energy_val > 18:
patt_thickness = 2600
elif energy_val > 16.5:
patt_thickness = 350
elif energy_val > 15:
patt_thickness = 1750
elif energy_val > 13.5:
patt_thickness = 1450
elif energy_val > 12:
patt_thickness = 850
else:
patt_thickness = 600
# setting patt1 motor positions
if ((patt_thickness ==3500) or (patt_thickness==2600) ):
patt1_pos = -29
elif ((patt_thickness == 600) or (patt_thickness==1450) or (patt_thickness==2350) ):
patt1_pos = -43
else:
patt1_pos = -15
# setting patt3 motor positions
if ( (patt_thickness == 3500) or (patt_thickness == 2350) or (patt_thickness == 1750) ):
patt3_pos = -29
elif ( (patt_thickness == 850) or (patt_thickness ==1450) or (patt_thickness ==2600) ):
patt3_pos = -43
else:
patt3_pos = -15
return [patt_thickness, patt1_pos, patt3_pos]
def calc_undulator(energy_target, undu):
# calculates using current harmonic and gap_offset
undu_position = setup_globals.eneund.controller.undu.energy2undulator(undu,energy_target)
return undu_position
def calc_hex1z(offset,layer):
# TODO: add offsets into the offset variable. But how to do with id26align_calc_param? A 3element list does not work!
if (layer == "Pd"):
hex1z_pos = offset - 11.8 # 14/09/2016 PG: changed from 12
elif (layer == "Pt"):
hex1z_pos = offset + 10.5 # 14/09/2016 PG: changed from 12
elif (layer == 'Si'):
hex1z_pos = offset
else:
print('undefined mirror layer')
hex1z_pos = None
#print(hex1z_pos)
return hex1z_pos
def calc_TY(offset, mono_type, hdm1_angle, hdm1_pos, mono_pos):
# deflection from the white beam axis because of HDM1
deflect = np.tan(2*hdm1_angle/1000)*(mono_pos-hdm1_pos)
#print(deflect)
# Mono TY -=21 for white beam on Si(111) and TY += 21 for Si(311)
if((mono_type == "Si111") or (mono_type == "Si333")):
TY_pos = deflect + offset - 21
elif (mono_type == 'Si311'): # i.e. Si311
TY_pos = deflect + offset + 21
else:
print('Mono type unknown')
TY_pos = None
return TY_pos
def calc_TH2(offset_111, offset_311, mono_type):
if((mono_type == "Si111") or (mono_type == "Si333")):
#TODO: replace by a calibration curve when available
TH2_pos = offset_111
elif (mono_type