Commit c2e048b4 authored by bliss administrator's avatar bliss administrator
Browse files

get rid of scripts/energy.py

ID26MonoMusstEncoders typo bug fix

MusstEncoderCalcHook bug fix

ID26MonoMusstEncoders energy conversion bug fix
parent 5cb160af
......@@ -1683,7 +1683,7 @@ class MusstEncoderCalcHook(CalcHook):
angle = (
mean * self.encoders[enc].direction
+ self.encoders[enc].offset["user"]
) / self.encoders[enc].factor
) / self.encoders[enc].steps_per_unit
ene = self.angletoenergy(angle)
output[f"{enc}_angle"].append(angle)
output[f"{enc}_energy"].append(ene)
......
import gevent
import math
from bliss.physics.units import ur
from bliss.controllers.moco import Moco
from bliss.config import static
from bliss import setup_globals
from id26.scripts.energy import g_mo_d as _get_g_mo_d
from id26.scripts.energy import energytoangle
class id26moco(Moco):
def __init__(self, name, config_tree):
......@@ -19,9 +18,10 @@ class id26moco(Moco):
def set_voltage(self):
self.outbeam("VOLT", "NORM", "UNIP", 10, "NOAUTO", silent=True)
self.slope = 1
self.slope = -1.3
self.phase = 100 # PG 25/08/2021
self.tau = 1
self.frequency = 40
print("MoCo box outbeam set to voltage.")
print(f"Slope set to {self.slope} and phase {self.phase}. You may check this using moco_scan(phase).")
......@@ -85,8 +85,8 @@ class id26moco(Moco):
percent = self.percentage
energy = setup_globals.energy
#g_mo_d = energy.controller.g_mo_d
g_mo_d = _get_g_mo_d()
xtals = energy.controller.mono.xtals
g_mo_d = (xtals.xtal[xtals.xtal_sel].d*ur.m).to("angstrom").magnitude
if g_mo_d > 3.0:
# energy resolution
......@@ -99,8 +99,7 @@ class id26moco(Moco):
resolution = 70000.0
ene_pos = energy.position
#bragg_pos = energy.controller.calc_to_real({"calc": ene_pos})["theta"]
bragg_pos = energytoangle(ene_pos)
bragg_pos = energy.controller.mono.energy2bragg(ene_pos)
winkel = math.radians(bragg_pos)
try:
......
from bliss.common import axis
from id26.scripts.beamline_settings import ID26Settings
from id26.scripts.energy import angletoenergy, energytoangle
class ID26MonoMusstEncoders:
......@@ -9,12 +8,10 @@ class ID26MonoMusstEncoders:
self.offset = ID26Settings (name, {'dial':0, 'user':0})
self.axis = config_dict['axis']
self.musst = config_dict['musst_controller']
self.factor = config_dict ['steps_per_unit']
self.direction = config_dict['direction']
self.channel = config_dict['musst_channel']
self.musst_name = config_dict['musst_controller'].name
self.musst_channel = config_dict['musst_channel']
self.steps_per_unit = config_dict['steps_per_unit']
self.direction = config_dict['direction']
self.name = name
def __info__(self):
......@@ -25,8 +22,8 @@ class ID26MonoMusstEncoders:
string += f' user: {self.offset["user"]}\n'
string += f'\naxis : {self.axis.name}'
string += f'\nmusst : {self.musst_name}'
string += f'\nchannel : {self.channel}'
string += f'\nfactor : {self.factor}'
string += f'\nchannel : {self.musst_channel}'
string += f'\nfactor : {self.steps_per_unit}'
string += f'\ndirection : {self.direction}'
string += f'\n'
......@@ -35,21 +32,21 @@ class ID26MonoMusstEncoders:
def calibrate (self, energy=None):
if energy:
theta = energytoangle (energy)
theta = self.dcm.energy2bragg(energy)
self.axis.position = theta
else:
self.axis.sync_hard()
self.offset['user'] = self.axis.position*self.factor - self.read()
self.offset['dial'] = self.axis.dial*self.factor - self.read()
self.offset['user'] = self.axis.position*self.steps_per_unit - self.read()
self.offset['dial'] = self.axis.dial*self.steps_per_unit - self.read()
def read (self):
return self.direction*int(self.musst.putget('?CH CH{0}'.format(self.channel)).split()[0])
return self.direction*int(self.musst_controller.putget('?CH CH{0}'.format(self.musst_channel)).split()[0])
def angle (self):
return (self.read() + self.offset['user']) / self.factor
return (self.read() + self.offset['user']) / self.steps_per_unit
def energy (self):
return (angletoenergy(self.angle()))
return (self.dcm.bragg2energy(self.angle()))
class ID26MonoMusstEncodersFix(ID26MonoMusstEncoders):
......
from bliss import setup_globals
from bliss.physics.units import ur
keV=ur.keV
deg=ur.deg
def energytosteps (energy):
#return angletosteps(energytoangle(energy))
return setup_globals.energy.controller.mono.energy2steps(energy)
def angletosteps (angle):
# MACROS qfscan2_common.mac steps = (angle + dial(mono,0)) * motor_par(mono, "step_size")
return (angle * setup_globals.mono.steps_per_unit)
def stepstoenergy (steps):
#return angletoenergy (stepstoangle (steps))
return setup_globals.energy.controller.mono.steps2energy (steps)
def stepstoangle (steps):
return steps/setup_globals.mono.steps_per_unit
def angletoenergy (angle):
#val = setup_globals.energy2.controller.crystal_plane.bragg_energy(angle*deg).to(keV).magnitude
val = setup_globals.energy.controller.mono.bragg2energy(angle)
return val
def energytoangle (energy):
#angle = setup_globals.energy2.controller.crystal_plane.bragg_angle(energy*keV).to(deg).magnitude
angle = setup_globals.energy.controller.mono.energy2bragg(energy)
return angle
def g_mo_d ():
#return setup_globals.energy2.controller.g_mo_d
xtals = setup_globals.energy.controller.mono.xtals
return (xtals.xtal[xtals.xtal_sel].d*ur.m).to("angstrom").magnitude
'''
SPEC
energy = hc_over_e / LAMBDA #in keV
LAMBDA = 2 * g_mo_d * sin(rad(A[Mono]))
theta = deg( asin( hc_over_e / energy * 2 * g_mo_d))
energy = hc_over_e / ((2 * a_elem * sin(rad(theta))) / (sqrt(h*h+k*k+l*l)))
g_mo_d = a_elem / (sqrt(h*h+k*k+l*l))
macros/id26align_menu.mac: if( ID26ALIGN["new_mono"] == "Si(111)" ) ID26ALIGN["g_mo_d"] = 3.13542
macros/id26align_menu.mac: if( ID26ALIGN["new_mono"] == "Si(311)" ) ID26ALIGN["g_mo_d"] = 1.63742
macros/id26align_menu.mac: if( ID26ALIGN["new_mono"] == "Si(333)" ) ID26ALIGN["g_mo_d"] = 1.04514
macros/id26align_menu.mac: mono_angle= deg( asin( hc_over_e / (ID26ALIGN["energy"]*2*ID26ALIGN["g_mo_d"]) ) )
macros/id26_analysers_tests.mac: ene = hc_over_e/((2*a_elem*sin(rad(theta)))/(sqrt(h*h+k*k+l*l)))
macros/id26_newEnergy_with_monox.mac: monox_delta_ene = monox_delta_pos * hc_over_e / (mono_vertical_shift * g_mo_d)
macros/id26_newEnergy_with_monox.mac: _monox_newpos = (_mono_vertical_shift * energy * g_mo_d) / hc_over_e
macros/id26_newEnergy_with_monox.mac: mono_angle = deg( asin( hc_over_e / (energie*2*g_mo_d) ) )
macros/id26_newEnergy_with_monox.mac: monox_newpos = (mono_vertical_shift * energie * g_mo_d) / hc_over_e
macros/id26_newEnergy_with_monox.mac: monox_delta_ene = fabs(A[monox] - monox_newpos) * hc_over_e / (mono_vertical_shift * g_mo_d)
macros/qfscan2_common.mac: angle = deg( asin ( hc_over_e / ( energy * 2 * g_mo_d ) ) )
macros/qfscan2_common.mac: energy = hc_over_e / ( sin(rad(angle)) * 2 * g_mo_d )
viola:~/local/spec % more spec.d/mono_settings
# Mono parameters last changed on Mon Dec 10 05:59:13 2018 by opid26
if (g_mo_d != 3.13542) {
print "Monochromator d-spacing is 3.13542 Angstroms."
qcomment "g_mo_d reset from %g to %g" "g_mo_d,3.13542"
}
constant g_mo_d 3.13542
../../spec/debian6/spec.d/standard.mac: LAMBDA = 2 * g_mo_d * sin(rad(A[Mono]))
../../spec/debian6/spec.d/standard.mac: printf(" d-spacing = %g Angstroms\n", g_mo_d)
'''
......@@ -6,7 +6,6 @@ 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
......@@ -38,6 +37,8 @@ _AXES_NAMES_DICT = {
}
DCM = setup_globals.dcm
if current_session.name in ['optics', 'eh2', 'texs']:
PVG = setup_globals.pvg
PVO = setup_globals.pvo
......@@ -366,9 +367,9 @@ class ID26Experiment(ID26Settings):
#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('mono', DCM.energy2bragg(self['energy']))
print('monox', setup_globals.monox_calc_ene(self["energy"]))
self['mono'] = energytoangle(self['energy'])
self['mono'] = DCM.energy2bragg(self['energy'])
self['monox'] = setup_globals.monox_calc_ene(self["energy"])
calc_hex1z_val = calc_hex1z(ID26ALIGN_CALC_PARAM['hex1z'],self['mirror_layers'])
......@@ -825,9 +826,9 @@ def calc_ppy(ppy_offset, hdm1_angle, ppy_pos, hex1_pos):
##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('mono', DCM.energy2bragg(self['energy']))
#print('monox', monox_calc_ene(self["energy"]))
#self['mono'] = energytoangle(self['energy'])
#self['mono'] = DCM.energy2bragg(self['energy'])
#self['monox'] = monox_calc_ene(self["energy"])
#calc_hex1z_val = calc_hex1z(ID26ALIGN_CALC_PARAM['hex1z'],self['mirror_layers'])
......@@ -1084,7 +1085,7 @@ def calc_ppy(ppy_offset, hdm1_angle, ppy_pos, hex1_pos):
#def check_mono_crystals(self):
#message = []
#if ( self["mono_crystals"] != "Uncertain" ):
#mono_angle= energytoangle(self["energy"])
#mono_angle= DCM.energy2bragg(self["energy"])
#if (mono_angle >= mono.low_limit and mono_angle <= mono.high_limit ):
#self["mono"] = mono_angle
#else:
......
import numpy
import time
from bliss.physics import trajectory
from bliss.common import axis
from id26.scripts.energy import energytoangle, energytosteps
class ID26FscanCyclicTrajectory(axis.CyclicTrajectory):
"""
I need to remove last point in PVT when serveral scan cycles, because we want to finish zap measurement on energy_end
energy incrementing
angles decrementing
delta
delta = target_pos - current_pos
backlash = self.backlash / self.sign * self.steps_per_unit
if backlash:
if abs(delta) > 0 and math.copysign(delta, backlash) != delta:
# move and backlash are not in the same direction; apply backlash correction, the move will happen in 2 steps
target_pos -= backlash
delta -= backlash
else:
backlash = 0
motion.backlash = backlash
"""
def __init__(self, *args, backlash=None, **kwargs):
self.backlash = backlash
super().__init__(*args, **kwargs)
@property
def pvt(self):
pvt = super().pvt
if self.is_closed: # OR self.nb_cycles>1
pvt = numpy.delete(pvt, len(pvt) - 1)
if self.backlash:
pos = pvt["position"]
delta = pos[1:] - pos[: len(pos) - 1]
check1 = delta > 0 if self.backlash < 0 else delta < 0
if check1[-1] is True:
raise RuntimeError(
"backlash cannot be completed at the end of[such scan"
)
pos[1:] -= check1 * self.backlash
pvt["position"] = pos
return pvt
@axis.lazy_init
def pm600_prog_mono_trajectory(
mono_axis,
energy_start,
energy_end,
duration,
nscans=1,
nintervals=10,
backlash=0,
delay=0,
id_linked=0,
id_acctime=0,
):
# group.prepare() --> gevent.spawn(controller._prepare_trajectory, *trajectories)
# controller=group.trajectories_by_controller.items()[0]
# controller=group.__trajectories_dialunit.axis.controller
# controller=p600_trajectory_cyclic.axis.controller
# controller._prepare_trajectory (motor.py)
# -> calls PM600.prepare_trajectory and PM600.set_trajectory_events
# group.prepare() --> pvt['position'] is converted to dial... trajectories.append(trajectory.convert_to_dial())
# so keep position in angle in my PVT
# print ('nintervals {0} would be accepted, but keep user input {1}'.format(int((127 - (nscans - 1)) / nscans), nintervals))
if nscans > 1:
duration += duration / nintervals
energy_end += (energy_end - energy_start) / nintervals
nintervals += 1
times = numpy.linspace(
0, duration, nintervals + 1
) # At t0 == 0 and t9 == duration seconds in (nintervals+1) points.
angles = energytoangle(
numpy.linspace(energy_start, energy_end, nintervals + 1)
) # degrees
if nscans > 1:
angles[len(angles) - 1] = angles[0]
# build PVT array and create trajectory object for mono axis:
traj = trajectory.PointTrajectory()
angles_c = angles - angles[0]
traj.build(times, {"PM600": angles_c})
pvt = traj.pvt()
pm600_trajectory_cyclic = ID26FscanCyclicTrajectory(
mono_axis, pvt["PM600"], backlash=backlash, nb_cycles=nscans, origin=angles[0]
)
# as pre_xp and post_xp are not passed to *trajectories, set them elsewhere in pm600 controller
# group.prepare() --> gevent.spawn(controller._prepare_trajectory, *trajectories)
# wont pass any other parameters....
# add pre_xp and post_xp pieces of sequences
# 1WP22222220 write port , i.e. send signal to opiom to start the zap
pre_xp = []
if id_linked:
pre_xp.append("WA0") # wait for last bit to be 0,= ID_moving
pre_xp.append(
f"DE{int(id_acctime*1000)}"
) # setup delay for ID acceleration time
pre_xp.append("WE") # wait delay ends
pre_xp.append("WP22222220") # write port, send signal to opiom to start the zap
pre_xp.append(
f"DE{delay*1000}"
) # setup delay before starting the profile (FSCAN_PAR['pm600_wp_delay'] and shutter delay in some cases)
pre_xp.append("WE") # wait delay ends
post_xp = ["WE", "WP22222221"]
# post_xp = ['WP22222222'] #just to read the OK after 1XS2
# do not move WP command to fscan_cleanup - that would make XS command not returning OK probably ...
# 1DExx set delay to wait acq finishes -> post_xp.add('DE{0}'.format(delay2))
# 1MAxx go back to steps0 if requested -> done by cleanup
# 1SVxx set back steady velocity -> done by cleanup
mono_axis.trajectory_pre_xp = pre_xp
mono_axis.trajectory_post_xp = post_xp
return pm600_trajectory_cyclic
@axis.lazy_init
def pm600_prog_white_opiom_trig(mono_axis):
pm600 = mono_axis
channel = pm600.channel
prf_num = pm600.trajectory_profile_number
seq_num = pm600.trajectory_sequence_number
# 1WP22222220 write port , i.e. send signal to opiom to start the zap
pre_xp = ["WP22222220"]
prog = [f"US{seq_num}", f"UP{prf_num}"] # undefine sequence # undefine profile
# PROFILE: no profile
# SEQUENCE: all commands allowed, and DS/ES
prog.append(f"DS{seq_num}")
for cmd in pre_xp:
prog.append(f"{cmd}")
prog.append(f"ES{seq_num}")
print(f"program ready to be loaded on channel {channel}: {prog}")
# pm600.controller.sock.flush()
for cmd in prog:
pm600.controller.raw_write_read(channel + cmd + "\r")
start_trajectory_cmd = f"{channel}XS{seq_num}\r"
pm600.controller.raw_write(f"{channel}LP{prf_num}\r{channel}LS{seq_num}\r")
time.sleep(1)
print("program loaded:", pm600.controller.sock.raw_read().decode())
return start_trajectory_cmd
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment