Startup
This commit is contained in:
382
script/__Lib/diffcalc-2.1/diffcalc/hardware.py
Executable file
382
script/__Lib/diffcalc-2.1/diffcalc/hardware.py
Executable file
@@ -0,0 +1,382 @@
|
||||
###
|
||||
# Copyright 2008-2011 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/>.
|
||||
###
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from diffcalc.util import DiffcalcException
|
||||
from diffcalc import settings
|
||||
|
||||
SMALL = 1e-8
|
||||
|
||||
from diffcalc.util import command
|
||||
|
||||
__all__ = ['hardware', 'setcut', 'setmin', 'setmax']
|
||||
|
||||
|
||||
def getNameFromScannableOrString(o):
|
||||
try: # it may be a scannable
|
||||
return o.getName()
|
||||
except AttributeError:
|
||||
return str(o)
|
||||
|
||||
|
||||
|
||||
@command
|
||||
def hardware():
|
||||
"""hardware -- show diffcalc limits and cuts"""
|
||||
print settings.hardware.repr_sector_limits_and_cuts() # @UndefinedVariable
|
||||
|
||||
@command
|
||||
def setcut(scannable_or_string=None, val=None):
|
||||
"""setcut {name {val}} -- sets cut angle
|
||||
"""
|
||||
if scannable_or_string is None and val is None:
|
||||
print settings.hardware.repr_sector_limits_and_cuts() # @UndefinedVariable
|
||||
else:
|
||||
name = getNameFromScannableOrString(scannable_or_string)
|
||||
if val is None:
|
||||
print '%s: %f' % (name, settings.hardware.get_cuts()[name]) # @UndefinedVariable
|
||||
else:
|
||||
oldcut = settings.hardware.get_cuts()[name] # @UndefinedVariable
|
||||
settings.hardware.set_cut(name, float(val)) # @UndefinedVariable
|
||||
newcut = settings.hardware.get_cuts()[name] # @UndefinedVariable
|
||||
|
||||
@command
|
||||
def setmin(name=None, val=None):
|
||||
"""setmin {axis {val}} -- set lower limits used by auto sector code (None to clear)""" #@IgnorePep8
|
||||
_setMinOrMax(name, val, settings.hardware.set_lower_limit) # @UndefinedVariable
|
||||
|
||||
@command
|
||||
def setmax(name=None, val=None):
|
||||
"""setmax {name {val}} -- sets upper limits used by auto sector code (None to clear)""" #@IgnorePep8
|
||||
_setMinOrMax(name, val, settings.hardware.set_upper_limit) # @UndefinedVariable
|
||||
|
||||
@command
|
||||
def setrange(name=None, lower=None, upper=None):
|
||||
"""setrange {axis {min} {max}} -- set lower and upper limits used by auto sector code (None to clear)""" #@IgnorePep8
|
||||
_setMinOrMax(name, lower, settings.hardware.set_lower_limit) # @UndefinedVariable
|
||||
_setMinOrMax(name, upper, settings.hardware.set_upper_limit) # @UndefinedVariable
|
||||
|
||||
def _setMinOrMax(name, val, setMethod):
|
||||
if name is None:
|
||||
print settings.hardware.repr_sector_limits_and_cuts() # @UndefinedVariable
|
||||
else:
|
||||
name = getNameFromScannableOrString(name)
|
||||
if val is None:
|
||||
print settings.hardware.repr_sector_limits_and_cuts(name) # @UndefinedVariable
|
||||
else:
|
||||
setMethod(name, float(val))
|
||||
|
||||
|
||||
commands_for_help = ['Hardware',
|
||||
hardware,
|
||||
setcut,
|
||||
setmin,
|
||||
setmax]
|
||||
|
||||
|
||||
class HardwareAdapter(object):
|
||||
|
||||
def __init__(self, diffractometerAngleNames, defaultCuts={},
|
||||
energyScannableMultiplierToGetKeV=1):
|
||||
|
||||
self._diffractometerAngleNames = diffractometerAngleNames
|
||||
self._upperLimitDict = {}
|
||||
self._lowerLimitDict = {}
|
||||
self._cut_angles = {}
|
||||
self._configure_cuts(defaultCuts)
|
||||
self.energyScannableMultiplierToGetKeV = \
|
||||
energyScannableMultiplierToGetKeV
|
||||
self._name = 'base'
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
def get_axes_names(self):
|
||||
return tuple(self._diffractometerAngleNames)
|
||||
|
||||
def get_position(self):
|
||||
"""pos = get_position() -- returns the current physical diffractometer
|
||||
position as a diffcalc.util object in degrees
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_wavelength(self):
|
||||
"""wavelength = get_wavelength() -- returns wavelength in Angstroms
|
||||
"""
|
||||
return 12.39842 / self.get_energy()
|
||||
|
||||
def get_energy(self):
|
||||
"""energy = get_energy() -- returns energy in kEv """
|
||||
raise NotImplementedError()
|
||||
|
||||
def __str__(self):
|
||||
s = self.name + ":\n"
|
||||
s += " energy : " + str(self.get_energy()) + " keV\n"
|
||||
s += " wavelength : " + str(self.get_wavelength()) + " Angstrom\n"
|
||||
names = self._diffractometerAngleNames
|
||||
for name, pos in zip(names, self.get_position()):
|
||||
s += " %s : %r deg\n" % (name, pos)
|
||||
return s
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def get_position_by_name(self, angleName):
|
||||
names = list(self._diffractometerAngleNames)
|
||||
return self.get_position()[names.index(angleName)]
|
||||
|
||||
### Limits ###
|
||||
|
||||
def get_lower_limit(self, name):
|
||||
'''returns lower limits by axis name. Limit may be None if not set
|
||||
'''
|
||||
if name not in self._diffractometerAngleNames:
|
||||
raise ValueError("No angle called %s. Try one of: %s" %
|
||||
(name, self._diffractometerAngleNames))
|
||||
return self._lowerLimitDict.get(name)
|
||||
|
||||
def get_upper_limit(self, name):
|
||||
'''returns upper limit by axis name. Limit may be None if not set
|
||||
'''
|
||||
if name not in self._diffractometerAngleNames:
|
||||
raise ValueError("No angle called %s. Try one of: %s" %
|
||||
name, self._diffractometerAngleNames)
|
||||
return self._upperLimitDict.get(name)
|
||||
|
||||
def set_lower_limit(self, name, value):
|
||||
"""value may be None to remove limit"""
|
||||
if name not in self._diffractometerAngleNames:
|
||||
raise ValueError(
|
||||
"Cannot set lower Diffcalc limit: No angle called %s. Try one "
|
||||
"of: %s" % (name, self._diffractometerAngleNames))
|
||||
if value is None:
|
||||
try:
|
||||
del self._lowerLimitDict[name]
|
||||
except KeyError:
|
||||
print ("WARNING: There was no lower Diffcalc limit %s set to "
|
||||
"clear" % name)
|
||||
else:
|
||||
self._lowerLimitDict[name] = value
|
||||
|
||||
def set_upper_limit(self, name, value):
|
||||
"""value may be None to remove limit"""
|
||||
if name not in self._diffractometerAngleNames:
|
||||
raise ValueError(
|
||||
"Cannot set upper Diffcalc limit: No angle called %s. Try one "
|
||||
"of: %s" % (name, self._diffractometerAngleNames))
|
||||
if value is None:
|
||||
try:
|
||||
del self._upperLimitDict[name]
|
||||
except KeyError:
|
||||
print ("WARNING: There was no upper Diffcalc limit %s set to "
|
||||
"clear" % name)
|
||||
else:
|
||||
self._upperLimitDict[name] = value
|
||||
|
||||
def is_position_within_limits(self, positionArray):
|
||||
"""
|
||||
where position array is in degrees and cut to be between -180 and 180
|
||||
"""
|
||||
names = self._diffractometerAngleNames
|
||||
for axis_name, value in zip(names, positionArray):
|
||||
if not self.is_axis_value_within_limits(axis_name, value):
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_axis_value_within_limits(self, axis_name, value):
|
||||
if axis_name in self._upperLimitDict:
|
||||
if value > self._upperLimitDict[axis_name]:
|
||||
return False
|
||||
if axis_name in self._lowerLimitDict:
|
||||
if value < self._lowerLimitDict[axis_name]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def repr_sector_limits_and_cuts(self, name=None):
|
||||
if name is None:
|
||||
s = ''
|
||||
for name in self.get_axes_names():
|
||||
s += self.repr_sector_limits_and_cuts(name) + '\n'
|
||||
s += "Note: When auto sector/transforms are used,\n "
|
||||
s += " cuts are applied before checking limits."
|
||||
return s
|
||||
# limits:
|
||||
low = self.get_lower_limit(name)
|
||||
high = self.get_upper_limit(name)
|
||||
s = ' '
|
||||
if low is not None:
|
||||
s += "% 6.1f <= " % low
|
||||
else:
|
||||
s += ' ' * 10
|
||||
s += '%5s' % name
|
||||
if high is not None:
|
||||
s += " <= % 6.1f" % high
|
||||
else:
|
||||
s += ' ' * 10
|
||||
# cuts:
|
||||
try:
|
||||
if self.get_cuts()[name] is not None:
|
||||
s += " (cut: % 6.1f)" % self.get_cuts()[name]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return s
|
||||
|
||||
### Cutting Stuff ###
|
||||
|
||||
def _configure_cuts(self, defaultCutsDict):
|
||||
# 1. Set default cut angles
|
||||
self._cut_angles = dict.fromkeys(self._diffractometerAngleNames, -180.)
|
||||
if 'phi' in self._cut_angles:
|
||||
self._cut_angles['phi'] = 0.
|
||||
# 2. Overide with user-specified cuts
|
||||
for name, val in defaultCutsDict.iteritems():
|
||||
self.set_cut(name, val)
|
||||
|
||||
def set_cut(self, name, value):
|
||||
if name in self._cut_angles:
|
||||
self._cut_angles[name] = value
|
||||
else:
|
||||
raise KeyError("Diffractometer has no angle %s. Try: %s." %
|
||||
(name, self._diffractometerAngleNames))
|
||||
|
||||
def get_cuts(self):
|
||||
return self._cut_angles
|
||||
|
||||
def cut_angles(self, positionArray):
|
||||
'''Assumes each angle in positionArray is between -360 and 360
|
||||
'''
|
||||
cutArray = []
|
||||
names = self._diffractometerAngleNames
|
||||
for axis_name, value in zip(names, positionArray):
|
||||
cutArray.append(self.cut_angle(axis_name, value))
|
||||
return tuple(cutArray)
|
||||
|
||||
def cut_angle(self, axis_name, value):
|
||||
cut_angle = self._cut_angles[axis_name]
|
||||
if cut_angle is None:
|
||||
return value
|
||||
return cut_angle_at(cut_angle, value)
|
||||
|
||||
|
||||
def cut_angle_at(cut_angle, value):
|
||||
if (cut_angle == 0 and (abs(value - 360) < SMALL) or
|
||||
(abs(value + 360) < SMALL) or
|
||||
(abs(value) < SMALL)):
|
||||
value = 0.
|
||||
if value < (cut_angle - SMALL):
|
||||
return value + 360.
|
||||
elif value >= cut_angle + 360. + SMALL:
|
||||
return value - 360.
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
class DummyHardwareAdapter(HardwareAdapter):
|
||||
|
||||
def __init__(self, diffractometerAngleNames):
|
||||
super(self.__class__, self).__init__(diffractometerAngleNames)
|
||||
# HardwareAdapter.__init__(self, diffractometerAngleNames)
|
||||
|
||||
self._position = [0.] * len(diffractometerAngleNames)
|
||||
self._wavelength = 1.
|
||||
self.energyScannableMultiplierToGetKeV = 1
|
||||
self._name = "Dummy"
|
||||
|
||||
# Required methods
|
||||
|
||||
def get_position(self):
|
||||
"""
|
||||
pos = getDiffractometerPosition() -- returns the current physical
|
||||
diffractometer position as a list in degrees
|
||||
"""
|
||||
return self._position
|
||||
|
||||
def _set_position(self, pos):
|
||||
assert len(pos) == len(self.get_axes_names()), \
|
||||
"Wrong length of input list"
|
||||
self._position = pos
|
||||
|
||||
position = property(get_position, _set_position)
|
||||
|
||||
def get_energy(self):
|
||||
"""energy = get_energy() -- returns energy in kEv """
|
||||
if self._wavelength is None:
|
||||
raise DiffcalcException(
|
||||
"Energy or wavelength have not been set")
|
||||
return (12.39842 /
|
||||
(self._wavelength * self.energyScannableMultiplierToGetKeV))
|
||||
|
||||
def _set_energy(self, energy):
|
||||
self._wavelength = 12.39842 / energy
|
||||
|
||||
energy = property(get_energy, _set_energy)
|
||||
|
||||
def get_wavelength(self):
|
||||
"""wavelength = get_wavelength() -- returns wavelength in Angstroms"""
|
||||
if self._wavelength is None:
|
||||
raise DiffcalcException(
|
||||
"Energy or wavelength have not been set")
|
||||
return self._wavelength
|
||||
|
||||
def _set_wavelength(self, wavelength):
|
||||
self._wavelength = wavelength
|
||||
|
||||
wavelength = property(get_wavelength, _set_wavelength)
|
||||
|
||||
|
||||
class ScannableHardwareAdapter(HardwareAdapter):
|
||||
|
||||
def __init__(self, diffractometerScannable, energyScannable,
|
||||
energyScannableMultiplierToGetKeV=1):
|
||||
input_names = diffractometerScannable.getInputNames()
|
||||
super(self.__class__, self).__init__(input_names)
|
||||
# HardwareAdapter.__init__(self, input_names)
|
||||
self.diffhw = diffractometerScannable
|
||||
self.energyhw = energyScannable
|
||||
self.energyScannableMultiplierToGetKeV = \
|
||||
energyScannableMultiplierToGetKeV
|
||||
self._name = "ScannableHarwdareMonitor"
|
||||
|
||||
# Required methods
|
||||
|
||||
def get_position(self):
|
||||
"""
|
||||
pos = getDiffractometerPosition() -- returns the current physical
|
||||
diffractometer position as a list in degrees
|
||||
"""
|
||||
return self.diffhw.getPosition()
|
||||
|
||||
def get_energy(self):
|
||||
"""energy = get_energy() -- returns energy in kEv (NOT eV!) """
|
||||
multiplier = self.energyScannableMultiplierToGetKeV
|
||||
energy = self.energyhw.getPosition() * multiplier
|
||||
if energy is None:
|
||||
raise DiffcalcException("Energy has not been set")
|
||||
return energy
|
||||
|
||||
def get_wavelength(self):
|
||||
"""wavelength = get_wavelength() -- returns wavelength in Angstroms"""
|
||||
energy = self.get_energy()
|
||||
return 12.39842 / energy
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.diffhw.getName()
|
||||
Reference in New Issue
Block a user