Startup
This commit is contained in:
0
script/__Lib/diffcalc/startup/beamlinespecific/__init__.py
Executable file
0
script/__Lib/diffcalc/startup/beamlinespecific/__init__.py
Executable file
71
script/__Lib/diffcalc/startup/beamlinespecific/azihkl.py
Executable file
71
script/__Lib/diffcalc/startup/beamlinespecific/azihkl.py
Executable file
@@ -0,0 +1,71 @@
|
||||
###
|
||||
# Copyright 2008-2018 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Diffcalc is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
import platform
|
||||
from diffcalc.util import DiffcalcException
|
||||
|
||||
DEBUG = False
|
||||
|
||||
try:
|
||||
from gda.device.scannable import ScannableBase
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import ScannableBase
|
||||
|
||||
from diffcalc.ub.ub import ubcalc, _to_column_vector_triple
|
||||
|
||||
|
||||
class _DynamicDocstringMetaclass(type):
|
||||
|
||||
def _get_doc(self):
|
||||
return AzihklClass.dynamic_docstring
|
||||
|
||||
__doc__ = property(_get_doc) # @ReservedAssignment
|
||||
|
||||
|
||||
class AzihklClass(ScannableBase):
|
||||
'Azimuthal reference reciprocal lattice vector'
|
||||
|
||||
if platform.system() != 'Java':
|
||||
__metaclass__ = _DynamicDocstringMetaclass # TODO: Removed to fix Jython
|
||||
|
||||
dynamic_docstring = 'Azimuthal reference reciprocal lattice vector'
|
||||
|
||||
def _get_doc(self):
|
||||
return AzihklClass.dynamic_docstring
|
||||
|
||||
__doc__ = property(_get_doc) # @ReservedAssignment
|
||||
|
||||
def __init__(self,name):
|
||||
self.setName(name)
|
||||
self.setLevel(3)
|
||||
self.setInputNames(['azih','azik','azil'])
|
||||
self.setOutputFormat(['%4.4f', '%4.4f','%4.4f'])
|
||||
|
||||
def asynchronousMoveTo(self,new_position):
|
||||
ref_matrix = _to_column_vector_triple(new_position)
|
||||
ubcalc.set_n_hkl_configured(ref_matrix)
|
||||
|
||||
def isBusy(self):
|
||||
return 0
|
||||
|
||||
def getPosition(self):
|
||||
try:
|
||||
ref_matrix = ubcalc.n_hkl
|
||||
return ref_matrix.T.tolist()[0]
|
||||
except DiffcalcException, e:
|
||||
print e
|
||||
430
script/__Lib/diffcalc/startup/beamlinespecific/i21.py
Executable file
430
script/__Lib/diffcalc/startup/beamlinespecific/i21.py
Executable file
@@ -0,0 +1,430 @@
|
||||
'''
|
||||
Created on 19 Feb 2017
|
||||
|
||||
@author: zrb13439
|
||||
'''
|
||||
from diffcalc import settings
|
||||
try:
|
||||
from gda.device.scannable.scannablegroup import \
|
||||
ScannableMotionWithScannableFieldsBase, ScannableBase
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableMotionWithScannableFieldsBase, ScannableBase
|
||||
from math import pi
|
||||
|
||||
# TP_HELP="""
|
||||
# Use the Scannables tplab, tplabx, tplaby, tplabz to move the configured tool point in
|
||||
# the lab frame. For example to move it to the centre of the diffractomter:
|
||||
#
|
||||
# >>> pos tplab [0 0 0] # Move the toolpoint
|
||||
#
|
||||
# use 'settp' to change the configured toolpoint in the phi frame:
|
||||
#
|
||||
# >>> pos tphi [0 0 1] # will not move anything
|
||||
#
|
||||
# or use it with no args to make the location in the phi frame currently in
|
||||
# the centre of the diffracomtter the tool point. i.e. to make the tblab
|
||||
# report back [0 0 0]
|
||||
# """
|
||||
TP_HELP="""
|
||||
For help with sa, tp_phi and tp_lab see: http://confluence.diamond.ac.uk/x/CBIAB
|
||||
"""
|
||||
|
||||
from diffcalc.hkl.you.constraints import NUNAME
|
||||
from diffcalc.hkl.you.geometry import calcETA, calcCHI, calcPHI, YouGeometry,\
|
||||
YouPosition
|
||||
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
DEBUG = False
|
||||
|
||||
def calc_tp_lab(tp_phi_tuple, eta, chi, phi, xyz_eta=[0, 0, 0]):
|
||||
tp_phi = matrix(tp_phi_tuple).T
|
||||
ETA = calcETA(eta * TORAD)
|
||||
CHI = calcCHI(chi * TORAD)
|
||||
PHI = calcPHI(phi * TORAD)
|
||||
xyz_eta = matrix(xyz_eta).T
|
||||
|
||||
tp_lab = ETA * (xyz_eta + (CHI * PHI * tp_phi))
|
||||
return list(tp_lab.T.tolist()[0])
|
||||
|
||||
|
||||
def calc_tp_eta(tp_phi_tuple, chi, phi):
|
||||
return calc_tp_lab(tp_phi_tuple, 0, chi, phi, [0, 0, 0])
|
||||
|
||||
|
||||
def move_lab_origin_into_phi(chi, phi, xyz_eta_tuple):
|
||||
# the inverse of calc_tp_lab with tp_lab=0:
|
||||
CHI = calcCHI(chi * TORAD)
|
||||
PHI = calcPHI(phi * TORAD)
|
||||
xyz_eta = matrix(xyz_eta_tuple).T
|
||||
try:
|
||||
#work in IPython with numpy
|
||||
tp_phi = PHI.I * CHI.I * (-1.0 * xyz_eta)
|
||||
except:
|
||||
# work in GDA using jama_matrix_wrapper - definitely not nice
|
||||
tp_phi = PHI.I * CHI.I * (xyz_eta.__mul__(-1.0))
|
||||
return list(tp_phi.T.tolist()[0])
|
||||
|
||||
|
||||
def _format_vector(vector, fmt = '%7.4f'):
|
||||
vals = [fmt % e for e in vector]
|
||||
return ' '.join(vals)
|
||||
|
||||
|
||||
class FourCircleI21(YouGeometry):
|
||||
"""For a diffractometer with angles:
|
||||
delta, eta, chi, phi
|
||||
"""
|
||||
def __init__(self, beamline_axes_transform=None, delta_offset=0):
|
||||
self._delta_offset = delta_offset
|
||||
YouGeometry.__init__(self, 'fourc', {'eta': 0, 'delta': 0}, beamline_axes_transform)
|
||||
|
||||
# Order should match scannable order in _fourc group for mapping to work correctly
|
||||
self._scn_mapping_to_int = ((NUNAME, lambda x: x + self._delta_offset),
|
||||
('mu', lambda x: x),
|
||||
('chi', lambda x: x),
|
||||
('phi', lambda x: -x))
|
||||
self._scn_mapping_to_ext = ((NUNAME, lambda x: x - self._delta_offset),
|
||||
('mu', lambda x: x),
|
||||
('chi', lambda x: x),
|
||||
('phi', lambda x: -x))
|
||||
|
||||
def map_to_internal_name(self, name):
|
||||
scn_names = settings.hardware.diffhw.getInputNames()
|
||||
try:
|
||||
idx_name = scn_names.index(name)
|
||||
you_name, _ = self._scn_mapping_to_int[idx_name]
|
||||
return you_name
|
||||
except ValueError:
|
||||
return name
|
||||
|
||||
def map_to_external_name(self, name):
|
||||
scn_names = settings.hardware.diffhw.getInputNames()
|
||||
for idx, (you_name, _) in enumerate(self._scn_mapping_to_ext):
|
||||
if you_name == name:
|
||||
return scn_names[idx]
|
||||
return name
|
||||
|
||||
def map_to_internal_position(self, name, value):
|
||||
scn_names = settings.hardware.diffhw.getInputNames()
|
||||
try:
|
||||
idx_name = scn_names.index(name)
|
||||
except ValueError:
|
||||
return name, value
|
||||
new_name, op = self._scn_mapping_to_int[idx_name]
|
||||
try:
|
||||
return new_name, op(value)
|
||||
except TypeError:
|
||||
return new_name, None
|
||||
|
||||
def map_to_external_position(self, name, value):
|
||||
try:
|
||||
(idx, _, op), = tuple((i, nm, o) for i, (nm, o) in enumerate(self._scn_mapping_to_ext) if nm == name)
|
||||
except ValueError:
|
||||
return name, value
|
||||
scn_names = settings.hardware.diffhw.getInputNames()
|
||||
try:
|
||||
ext_name = scn_names[idx]
|
||||
except ValueError:
|
||||
return name, value
|
||||
try:
|
||||
return ext_name, op(value)
|
||||
except TypeError:
|
||||
return ext_name, None
|
||||
|
||||
def physical_angles_to_internal_position(self, physical_angle_tuple):
|
||||
you_angles = {}
|
||||
scn_names = settings.hardware.diffhw.getInputNames()
|
||||
for scn_name, phys_angle in zip(scn_names, physical_angle_tuple):
|
||||
name, val = self.map_to_internal_position(scn_name, phys_angle)
|
||||
you_angles[name] = val
|
||||
you_angles.update(self.fixed_constraints)
|
||||
|
||||
angle_values = tuple(you_angles[name] for name in YouPosition.get_names())
|
||||
return YouPosition(*angle_values, unit='DEG')
|
||||
|
||||
def internal_position_to_physical_angles(self, internal_position):
|
||||
clone_position = internal_position.clone()
|
||||
clone_position.changeToDegrees()
|
||||
you_angles = clone_position.todict()
|
||||
res = []
|
||||
for name, _ in self._scn_mapping_to_ext:
|
||||
_, val = self.map_to_external_position(name, you_angles[name])
|
||||
res.append(val)
|
||||
return tuple(res)
|
||||
|
||||
|
||||
class I21SampleStage(ScannableMotionWithScannableFieldsBase):
|
||||
|
||||
def __init__(self, name, pol_scn, tilt_scn, az_scn, xyz_eta_scn):
|
||||
|
||||
self.setName(name)
|
||||
self._scn_list = [pol_scn, tilt_scn, az_scn]
|
||||
self.xyz_eta_scn = xyz_eta_scn
|
||||
|
||||
self.setInputNames([pol_scn.getName(), tilt_scn.getName(), az_scn.getName()]) # note, names copied below
|
||||
self.setOutputFormat(['%7.5f'] * 3)
|
||||
self.completeInstantiation()
|
||||
|
||||
# tp_phi is the TARGET tool point to end up at the diffractometer centre
|
||||
self.tp_phi = [0, 0, 0]
|
||||
|
||||
self.tp_phi_scannable = I21SampleStage.TpPhiScannable('tp_phi', self)
|
||||
self.centre_toolpoint = True
|
||||
|
||||
def asynchronousMoveTo(self, pos_triple):
|
||||
|
||||
if len(pos_triple) != 3:
|
||||
raise ValueError(self.getName() + ' device expects three inputs')
|
||||
|
||||
# Move pol, tilt & az (None if not to be moved)
|
||||
pol, tilt, az = pos_triple
|
||||
if pol is not None:
|
||||
self._scn_list[0].asynchronousMoveTo(pol)
|
||||
if tilt is not None:
|
||||
self._scn_list[1].asynchronousMoveTo(tilt)
|
||||
if az is not None:
|
||||
self._scn_list[2].asynchronousMoveTo(az)
|
||||
|
||||
if self.centre_toolpoint:
|
||||
_, tilt, az = self.completePosition(pos_triple)
|
||||
chi = tilt
|
||||
phi = az
|
||||
tp_offset_eta = calc_tp_eta(self.tp_phi, chi, phi)
|
||||
if DEBUG:
|
||||
print ('{Correcting xyz_eta for '
|
||||
'tilt(chi)=%.2f & az(phi)=%.2f}' % (tilt, az)).rjust(79)
|
||||
xyz = [-1 * e for e in tp_offset_eta]
|
||||
self.xyz_eta_scn.asynchronousMoveTo(xyz)
|
||||
|
||||
def rawGetPosition(self):
|
||||
return [scn.getPosition() for scn in self._scn_list]
|
||||
|
||||
def getFieldPosition(self, i):
|
||||
return self._scn_list[i].getPosition()
|
||||
|
||||
def isBusy(self):
|
||||
return (any([scn.isBusy() for scn in self._scn_list])
|
||||
or self.xyz_eta_scn.isBusy())
|
||||
|
||||
def waitWhileBusy(self):
|
||||
for scn in self._scn_list:
|
||||
scn.waitWhileBusy()
|
||||
self.xyz_eta_scn.waitWhileBusy()
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
# Sample angle columns
|
||||
pos = self.getPosition()
|
||||
formatted_values = self.formatPositionFields(pos)
|
||||
|
||||
sa_col = []
|
||||
sa_col.append('%s:' % self.getName())
|
||||
sa_col.append('%s: %s (eta)' % (self._scn_list[0].getName(),formatted_values[0]))
|
||||
sa_col.append('%s: %s (chi)' % (self._scn_list[1].getName(),formatted_values[1]))
|
||||
sa_col.append('%s: %s (phi)' % (self._scn_list[2].getName(),formatted_values[2]))
|
||||
sa_col_width = len(sa_col[2])
|
||||
|
||||
# Toolpoint column
|
||||
xyz_eta = list(self.xyz_eta_scn.getPosition())
|
||||
eta, chi, phi = self.getEulerPosition()
|
||||
tp_lab = calc_tp_lab(self.tp_phi, eta, chi, phi, xyz_eta)
|
||||
|
||||
tp_col = []
|
||||
tp_col.append('')
|
||||
tp_col.append('tp_phi : %s (set)' % _format_vector(self.tp_phi))
|
||||
tp_col.append('tp_lab : %s' % _format_vector(tp_lab))
|
||||
tp_col.append('xyz_eta: %s' % _format_vector(xyz_eta))
|
||||
|
||||
# Combine columns
|
||||
lines = []
|
||||
while sa_col or tp_col:
|
||||
sa_row = sa_col.pop(0) if sa_col else ''
|
||||
tp_row = tp_col.pop(0) if tp_col else ''
|
||||
lines.append(sa_row.ljust(sa_col_width + 3) + tp_row)
|
||||
|
||||
if self.centre_toolpoint:
|
||||
lines.append("\nToolpoint centring ENABLED (disable with toolpoint_off)")
|
||||
else:
|
||||
lines.append("\nToolpoint centring DISABLED (enable with toolpoint_on)")
|
||||
# Add some help
|
||||
return '\n'.join(lines) + TP_HELP
|
||||
|
||||
def getEulerPosition(self):
|
||||
pol, tilt, az = self.getPosition()
|
||||
eta, chi, phi = pol, tilt, az
|
||||
return eta, chi, phi
|
||||
|
||||
class TpPhiScannable(ScannableBase):
|
||||
|
||||
def __init__(self, name, i21_sample_stage):
|
||||
self.name = name
|
||||
self.i21_sample_stage = i21_sample_stage
|
||||
self.inputNames = [name + 'x', name +'y', name + 'z']
|
||||
self.outputFormat = ['% 6.4f'] * 3
|
||||
self.level = 3
|
||||
|
||||
def isBusy(self):
|
||||
return False
|
||||
|
||||
def waitWhileBusy(self):
|
||||
return
|
||||
|
||||
def asynchronousMoveTo(self, new_position):
|
||||
if len(new_position) != 3:
|
||||
raise TypeError('Expected 3 element target')
|
||||
self.i21_sample_stage.tp_phi = list(new_position)
|
||||
|
||||
def getPosition(self):
|
||||
return list(self.i21_sample_stage.tp_phi)
|
||||
|
||||
def zerosample(self):
|
||||
"""Calculate tp_phi from the currently centred sample location."""
|
||||
_, chi, phi = self.getEulerPosition()
|
||||
xyz_eta_tuple = list(self.xyz_eta_scn.getPosition())
|
||||
tp_phi = move_lab_origin_into_phi(chi, phi, xyz_eta_tuple)
|
||||
self.tp_phi = tp_phi
|
||||
print "tp_phi set to: %s" % tp_phi
|
||||
|
||||
def centresample(self):
|
||||
"""Centre the sample. Equivilent to moving sa to its current position."""
|
||||
self.asynchronousMoveTo([None, None, None])
|
||||
self.waitWhileBusy()
|
||||
|
||||
|
||||
class I21DiffractometerStage(ScannableMotionWithScannableFieldsBase):
|
||||
|
||||
def __init__(self, name, delta_scn, sample_stage_scn, delta_offset=0):
|
||||
"""Create diffractomter stage from 3circle sample axes and a
|
||||
delta/tth axis.
|
||||
|
||||
Both the chi and delta offsets are added to underlying scannable values
|
||||
when *reading* the position. iu the same offset is subtracted when
|
||||
*setting* the position.
|
||||
"""
|
||||
|
||||
self.sample_stage_scn = sample_stage_scn
|
||||
self.delta_scn = delta_scn
|
||||
self.delta_offset = delta_offset
|
||||
self.setName(name)
|
||||
|
||||
self.setInputNames(['delta', 'eta', 'chi', 'phi']) # note, names copied below
|
||||
self.setOutputFormat(['%7.4f'] * 4)
|
||||
self.completeInstantiation()
|
||||
|
||||
def asynchronousMoveTo(self, pos_quadruple):
|
||||
if len(pos_quadruple) != 4:
|
||||
raise ValueError(self.getName() + ' device expects four inputs')
|
||||
|
||||
delta, eta, chi, phi = pos_quadruple
|
||||
pol = eta
|
||||
#TODO revert to 'chi - self.chi_offset'once EPICS sign fixed
|
||||
tilt = chi
|
||||
az = phi
|
||||
|
||||
if delta is not None:
|
||||
self.delta_scn.asynchronousMoveTo(delta - self.delta_offset)
|
||||
|
||||
if (pol is not None) or (tilt is not None) or (az is not None):
|
||||
self.sample_stage_scn.asynchronousMoveTo([pol, tilt, az])
|
||||
|
||||
def rawGetPosition(self):
|
||||
delta = self.delta_scn.getPosition()
|
||||
pol, tilt, az = self.sample_stage_scn.getPosition()
|
||||
eta, chi, phi = pol, tilt, az
|
||||
return delta + self.delta_offset, eta, chi, phi
|
||||
|
||||
def getFieldPosition(self, i):
|
||||
return self.getPosition()[i]
|
||||
|
||||
def isBusy(self):
|
||||
return self.delta_scn.isBusy() or self.sample_stage_scn.isBusy()
|
||||
|
||||
def waitWhileBusy(self):
|
||||
self.delta_scn.waitWhileBusy()
|
||||
self.sample_stage_scn.waitWhileBusy()
|
||||
|
||||
def __repr__(self):
|
||||
vals = self.formatPositionFields(self.getPosition())
|
||||
lines = []
|
||||
for name, val, hint in zip(self.getInputNames(), vals, self.get_hints()):
|
||||
lines.append('%-6s : %s%s' % (name, val, hint))
|
||||
return '\n'.join(lines)
|
||||
|
||||
def get_hints(self):
|
||||
sample_names = self.sample_stage_scn.getInputNames()
|
||||
hints = []
|
||||
if self.delta_offset != 0:
|
||||
sign = '+' if self.delta_offset > 0 else '-'
|
||||
hints.append(' (%s %s %s)' %
|
||||
(self.delta_scn.getName(), sign, abs(self.delta_offset))) # delta
|
||||
else:
|
||||
hints.append(' (%s)' % self.delta_scn.getName()) # delta
|
||||
hints.append(' (%s)' % sample_names[0]) # eta
|
||||
hints.append(' (%s)' % sample_names[1]) # chi
|
||||
hints.append(' (%s)' % sample_names[2]) # phi
|
||||
return hints
|
||||
|
||||
|
||||
class I21TPLab(ScannableMotionWithScannableFieldsBase):
|
||||
|
||||
def __init__(self, name, sample_stage_scn):
|
||||
|
||||
self.name = name
|
||||
self.sample_stage_scn = sample_stage_scn
|
||||
|
||||
self.setInputNames([name + 'x', name + 'y', name + 'z']) # note, names copied below
|
||||
self.setOutputFormat(['%7.4f'] * 3)
|
||||
self.completeInstantiation()
|
||||
self.setAutoCompletePartialMoveToTargets(True)
|
||||
|
||||
|
||||
def rawAsynchronousMoveTo(self, tp_lab_target):
|
||||
if len(tp_lab_target) != 3:
|
||||
raise ValueError(self.getName() + ' device expects three inputs')
|
||||
|
||||
if None in tp_lab_target:
|
||||
raise ValueError('unexpected None in tp_lab_target: ', tp_lab_target)
|
||||
|
||||
eta, chi, phi = self.sample_stage_scn.getEulerPosition()
|
||||
ETA = calcETA(eta * TORAD)
|
||||
|
||||
# Move tp target from lab frame inwards to eta frame
|
||||
tp_lab_target = matrix(tp_lab_target).T
|
||||
tp_eta_target = ETA.T * tp_lab_target # ETA.I == ETA.T
|
||||
|
||||
# Move configured tp from phi frame outwards to eta frame
|
||||
tp_eta = calc_tp_eta(self.sample_stage_scn.tp_phi, chi, phi)
|
||||
|
||||
# Calculate offset required to align the two
|
||||
xyz_eta = tp_eta_target - matrix(tp_eta).T
|
||||
xyz_eta = xyz_eta.T.tolist()[0]
|
||||
|
||||
self.sample_stage_scn.xyz_eta_scn.asynchronousMoveTo(xyz_eta)
|
||||
|
||||
def rawGetPosition(self):
|
||||
tp_phi = list(self.sample_stage_scn.tp_phi)
|
||||
eta, chi, phi = self.sample_stage_scn.getEulerPosition()
|
||||
xyz_eta = list(self.sample_stage_scn.xyz_eta_scn.getPosition())
|
||||
|
||||
tp_lab = calc_tp_lab(tp_phi, eta, chi, phi, xyz_eta)
|
||||
return tp_lab
|
||||
|
||||
def getFieldPosition(self, i):
|
||||
return self.getPosition()[i]
|
||||
|
||||
def isBusy(self):
|
||||
return self.sample_stage_scn.xyz_eta_scn.isBusy()
|
||||
|
||||
def waitWhileBusy(self):
|
||||
self.sample_stage_scn.xyz_eta_scn.waitWhileBusy()
|
||||
|
||||
Reference in New Issue
Block a user